Skip to content

Commit

Permalink
🧱(cookiecutter) select databases to run sites
Browse files Browse the repository at this point in the history
- Changed the activate script to provide also the possibility of
select the database to build the app

- The intention is to provide flexibility to fetch images from a given
dockerhub, and when it is not provided, the dockerhub continues following the
standard which is fundocker.
  • Loading branch information
Tiago-Salles committed Feb 4, 2025
1 parent 657d0da commit e6e2931
Show file tree
Hide file tree
Showing 32 changed files with 8,827 additions and 372 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ Versioning](https://semver.org/spec/v2.0.0.html).
- Add Additional Information section for a category and
use them in a course page
- Added new page extension `MainMenuEntry`
- Added database selection to activate script
- Added org_dockerhub parameter to cookiecutter

### Fixed

Expand Down
4 changes: 4 additions & 0 deletions cookiecutter/cookiecutter.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
{
"organization": null,
"org_dockerhub": "fundocker",
"nginx_image_name": "fundocker/openshift-nginx",
"nginx_image_tag": "1.13",
"elasticsearch_image_name": "fundocker/openshift-elasticsearch:6.6.2",
"_copy_without_render": [
".circleci",
"bin/activate",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,39 +75,39 @@ hub:
- run:
name: Tag app image
command: |
docker images fundocker/<< parameters.image_name >>
docker images {{cookiecutter.org_dockerhub}}/<< parameters.image_name >>
# Display either:
# - DOCKER_TAG: main (Git branch)
# or
# - DOCKER_TAG: 1.1.2 (Git tag v1.1.2)
echo "DOCKER_TAG: ${DOCKER_TAG}"
docker tag << parameters.site >>:production fundocker/<< parameters.image_name >>:${DOCKER_TAG}
docker tag << parameters.site >>:production {{cookiecutter.org_dockerhub}}/<< parameters.image_name >>:${DOCKER_TAG}
if [[ -n "$CIRCLE_TAG" ]]; then
docker tag << parameters.site >>:production fundocker/<< parameters.image_name >>:latest
docker tag << parameters.site >>:production {{cookiecutter.org_dockerhub}}/<< parameters.image_name >>:latest
fi
docker images | grep -E "^fundocker/<< parameters.image_name >>\s*(${DOCKER_TAG}.*|latest|main)"
docker images | grep -E "^{{cookiecutter.org_dockerhub}}/<< parameters.image_name >>\s*(${DOCKER_TAG}.*|latest|main)"
- run:
name: Tag nginx image
command: |
docker images fundocker/<< parameters.image_name >>-nginx
docker images {{cookiecutter.org_dockerhub}}/<< parameters.image_name >>-nginx
echo "DOCKER_TAG: ${DOCKER_TAG}"
docker tag << parameters.site >>-nginx:production fundocker/<< parameters.image_name >>-nginx:${DOCKER_TAG}
docker tag << parameters.site >>-nginx:production {{cookiecutter.org_dockerhub}}/<< parameters.image_name >>-nginx:${DOCKER_TAG}
if [[ -n "$CIRCLE_TAG" ]]; then
docker tag << parameters.site >>-nginx:production fundocker/<< parameters.image_name >>-nginx:latest
docker tag << parameters.site >>-nginx:production {{cookiecutter.org_dockerhub}}/<< parameters.image_name >>-nginx:latest
fi
docker images | grep -E "^fundocker/<< parameters.image_name >>-nginx\s*(${DOCKER_TAG}.*|latest|main)"
docker images | grep -E "^{{cookiecutter.org_dockerhub}}/<< parameters.image_name >>-nginx\s*(${DOCKER_TAG}.*|latest|main)"
# Publish images
- run:
name: Publish app image
command: |
docker push fundocker/<< parameters.image_name >>:${DOCKER_TAG}
docker push {{cookiecutter.org_dockerhub}}/<< parameters.image_name >>:${DOCKER_TAG}
if [[ -n "$CIRCLE_TAG" ]]; then
docker push fundocker/<< parameters.image_name >>:latest
docker push {{cookiecutter.org_dockerhub}}/<< parameters.image_name >>:latest
fi
- run:
name: Publish nginx image
command: |
docker push fundocker/<< parameters.image_name >>-nginx:${DOCKER_TAG}
docker push {{cookiecutter.org_dockerhub}}/<< parameters.image_name >>-nginx:${DOCKER_TAG}
if [[ -n "$CIRCLE_TAG" ]]; then
docker push fundocker/<< parameters.image_name >>-nginx:latest
docker push {{cookiecutter.org_dockerhub}}/<< parameters.image_name >>-nginx:latest
fi
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
default_context:
_organization: {{cookiecutter.organization}}
_org_dockerhub: {{cookiecutter.org_dockerhub}}
_nginx_image_name: {{cookiecutter.nginx_image_name}}
_nginx_image_tag: {{cookiecutter.nginx_image_tag}}
_elasticsearch_image_name: {{cookiecutter.elasticsearch_image_name}}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
ARG NGINX_IMAGE_NAME=fundocker/openshift-nginx
ARG NGINX_IMAGE_TAG=1.13
ARG NGINX_IMAGE_NAME={{cookiecutter.nginx_image_name}}
ARG NGINX_IMAGE_TAG={{cookiecutter.nginx_image_tag}}
ARG STATIC_ROOT=/data/static
ARG SITE

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# -- Load .env file
ifneq (,$(wildcard .env))
include .env
export $(shell sed 's/=.*//' .env)
endif

# -- Terminal colors
COLOR_INFO = \033[0;36m
COLOR_RESET = \033[0m
Expand All @@ -13,15 +19,13 @@ COMPOSE = \
NGINX_IMAGE_TAG="$(NGINX_IMAGE_TAG)" \
DOCKER_USER="$(DOCKER_UID):$(DOCKER_GID)" \
docker compose
COMPOSE_UP_WAIT = $(COMPOSE) up -d --wait --wait-timeout 60
COMPOSE_RUN = $(COMPOSE) run --rm
COMPOSE_RUN_APP = $(COMPOSE_RUN) app-dev
COMPOSE_EXEC = $(COMPOSE) exec
COMPOSE_EXEC_APP = $(COMPOSE_EXEC) app-dev
COMPOSE_TEST_RUN = $(COMPOSE) run --rm -e DJANGO_CONFIGURATION=Test
COMPOSE_TEST_RUN_APP = $(COMPOSE_TEST_RUN) app-dev
WAIT_DB = $(COMPOSE_RUN) dockerize -wait tcp://db:5432 -timeout 60s
WAIT_ES = $(COMPOSE_RUN) dockerize -wait tcp://elasticsearch:9200 -timeout 60s
WAIT_SENTINEL = $(COMPOSE_RUN) dockerize -wait tcp://redis-sentinel:26379 -wait tcp://redis-primary:6379 -timeout 20s

# -- Node

Expand All @@ -44,7 +48,7 @@ bootstrap: \
env.d/aws \
env.d/development \
data/media/$(RICHIE_SITE)/.keep \
data/db/$(RICHIE_SITE) \
data/${ACTIVATED_DB}/$(RICHIE_SITE) \
stop \
build-front \
build \
Expand Down Expand Up @@ -84,7 +88,7 @@ build: .env ## build all containers
reset: .env ## Remove database and local files
$(COMPOSE) stop
rm -Ir data/* || exit 0
$(COMPOSE) rm db
$(COMPOSE) rm ${ACTIVATED_DB}
.PHONY: reset

down: .env ## stop & remove containers
Expand All @@ -96,11 +100,9 @@ logs: .env ## display app logs (follow mode)
.PHONY: logs

run: .env ## start the wsgi (production) or development server
@$(COMPOSE) up -V -d redis-sentinel
@$(WAIT_SENTINEL)
@$(COMPOSE) up -d nginx
@$(COMPOSE) up -d app-dev
@$(WAIT_DB)
@$(COMPOSE_UP_WAIT) -V redis-sentinel
@$(COMPOSE_UP_WAIT) nginx
@$(COMPOSE_UP_WAIT) app-dev
.PHONY: run

stop: .env ## stop the development server
Expand Down Expand Up @@ -179,8 +181,7 @@ check: .env ## perform django checks
.PHONY: check

demo-site: .env ## create a demo site
@$(COMPOSE) up -d db
@$(WAIT_DB)
@$(COMPOSE_UP_WAIT) ${ACTIVATED_DB}
@$(MANAGE) flush
@$(MANAGE) create_demo_site
@${MAKE} search-index
Expand Down Expand Up @@ -255,20 +256,20 @@ i18n-front: .env ## Extract and compile translation files used for react-intl
.PHONY: i18n-front

migrate: .env ## perform database migrations
@$(COMPOSE) up -d db
@$(WAIT_DB)
@echo "Start and wait for ${ACTIVATED_DB} to be up..."
@$(COMPOSE_UP_WAIT) ${ACTIVATED_DB}
@$(MANAGE) migrate
.PHONY: migrate

search-index: .env ## (re)generate the Elasticsearch index
@$(COMPOSE) up -d elasticsearch
@$(WAIT_ES)
@echo "Start and wait for ${ACTIVATED_DB} & elasticsearch to be up..."
@$(COMPOSE_UP_WAIT) elasticsearch
@$(MANAGE) bootstrap_elasticsearch
.PHONY: search-index

superuser: .env ## create a DjangoCMS superuser
@$(COMPOSE) up -d db
@$(WAIT_DB)
superuser: .env ## Create an admin user with password "admin"
@echo "Start and wait for ${ACTIVATED_DB} to be up..."
@$(COMPOSE_UP_WAIT) ${ACTIVATED_DB}
@$(MANAGE) createsuperuser
.PHONY: superuser

Expand All @@ -278,8 +279,7 @@ ci-check: .env ## run django check management command on productin image
.PHONY: ci-check

ci-migrate: .env ## run django migrate command on production image
@$(COMPOSE) up -d db
@$(WAIT_DB)
@$(COMPOSE) up -d ${ACTIVATED_DB}
$(COMPOSE_RUN) app python manage.py migrate
.PHONY: ci-migrate

Expand All @@ -306,9 +306,9 @@ data/media/$(RICHIE_SITE)/.keep: .env
@mkdir -p data/media/$(RICHIE_SITE)
@touch data/media/$(RICHIE_SITE)/.keep

data/db/$(RICHIE_SITE): .env
@echo 'Preparing db volume...'
@mkdir -p data/db/$(RICHIE_SITE)
data/${ACTIVATED_DB}/$(RICHIE_SITE): .env
@echo 'Preparing ${ACTIVATED_DB} volume...'
@mkdir -p data/${ACTIVATED_DB}/$(RICHIE_SITE)

env.d/development:
cp env.d/development.dist env.d/development
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,34 @@ declare -a sites
declare -i default=1
declare -i choice
declare -i n_sites
declare -a databases=("mysql" "postgresql" "sqlite")
declare -i database_choice
declare -i n_databases
declare -A languages=(
["Portuguese"]='("pt", "Portuguese")'
["Portuguese (Brazil)"]='("pt-br", "Portuguese (Brazil)")'
["French"]='("fr", "French (France)")'
["Spanish"]='("es", "Spanish")'
["Russian"]='("ru", "Russian")'
["Vietnamese"]='("vi", "Vietnamese")'
["Arabic (Saudi Arabia)"]='("ar", "Arabic (Saudi Arabia)")'
["Korean"]='("ko", "Korean")'
)
declare -A selected_languages=(
["English"]='("en", "English")'
)
ordered_languages=(
"English"
"Portuguese"
"Portuguese (Brazil)"
"French (France)"
"Spanish"
"Russian"
"Vietnamese"
"Arabic (Saudi Arabia)"
"Korean"
)
ordered_languages_choices=""

# List sites by looking in the "sites" directory
# and store them in an array
Expand All @@ -17,37 +45,99 @@ read -r -a sites <<< "$(
xargs
)"
n_sites=${#sites[@]}
n_databases=${#databases[@]}

if [[ n_sites -eq 0 ]]; then
(>&2 echo "You should first add a site to the project by running: make add-site")
exit 10
fi

if [[ n_sites -eq 1 ]]; then
# If there is only one site, just activate it
# If there is only one site, activate it
echo "RICHIE_SITE=${sites[0]}" > .env
exit 0
else
prompt="Select an available site to activate:\\n"
for (( i=0; i<n_sites; i++ )); do
prompt+="[$((i+1))] ${sites[$i]}"
if [[ $((i+1)) -eq ${default} ]]; then
prompt+=" (default)"
fi
prompt+="\\n"
done
prompt+="Your choice: "
read -r -p "$(echo -e "${prompt}")" choice

if [[ ${choice} -gt n_sites ]]; then
(>&2 echo "Invalid choice ${choice} (should be <= ${n_sites})")
exit 10
fi

if [[ ${choice} -le 0 ]]; then
choice=${default}
fi
fi

prompt="Select an available site to activate:\\n"
for (( i=0; i<n_sites; i++ )); do
prompt+="[$((i+1))] ${sites[$i]}"
prompt="Select an available database to activate:\\n"
for (( i=0; i<n_databases; i++ )); do
prompt+="[$((i+1))] ${databases[$i]}"
if [[ $((i+1)) -eq ${default} ]]; then
prompt+=" (default)"
fi
prompt+="\\n"
done
prompt+="Your choice: "
read -r -p "$(echo -e "${prompt}")" choice

if [[ ${choice} -gt n_sites ]]; then
(>&2 echo "Invalid choice ${choice} (should be <= ${n_sites})")
exit 10
fi
read -r -p "$(echo -e "${prompt}")" database_choice

if [[ ${choice} -le 0 ]]; then
choice=${default}
database_choice=${default}
fi

echo "Select the languages this site will support:"
for language in "${!languages[@]}"; do
while true; do
read -p "Enable $language? (y/n): " answer
if [[ "$answer" != "y" && "$answer" != "n" ]]; then
echo "Please enter 'y' or 'n'."
else
if [[ "$answer" == "y" ]]; then
selected_languages["$language"]="${languages["$language"]}"
fi
break
fi
done
done

for language in "${ordered_languages[@]}"; do
if [[ -n "${selected_languages["$language"]}" ]]; then
if [[ -z $ordered_languages_choices ]]; then
ordered_languages_choices="${selected_languages["$language"]}"
else
ordered_languages_choices="$ordered_languages_choices, ${selected_languages["$language"]}"
fi
fi
done

# Activate the chosen site
# Set the database and port
# Set the LANGUAGES variables
echo "RICHIE_SITE=${sites[$((choice-1))]}" > .env
echo "ACTIVATED_DB=${databases[$((database_choice-1))]}" >> .env

if [[ ${database_choice} == 1 ]]; then
echo "DB_PORT=3306" >> .env
else [[ ${database_choice} == 2 ]];
echo "DB_PORT=5472" >> .env
fi

echo "LANGUAGES=($ordered_languages_choices)" >> .env

echo """
Site activated successfully!
The configurations are set in the .env file
Please, note that you can change the languages
order in the .env file according to your needs.
English is the default language and if the site
will not suport it, you can remove it from there.
"""
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
services:
mysql:
image: mysql:8.0
ports:
- "3306:3306"
environment:
- MYSQL_ALLOW_EMPTY_PASSWORD=yes
- MYSQL_ROOT_PASSWORD=
- MYSQL_DATABASE=richie_${RICHIE_SITE:?}
command: --default-authentication-plugin=caching_sha2_password
healthcheck:
test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
interval: 1s
timeout: 2s
retries: 300
volumes:
- ./data/db/${RICHIE_SITE:?}:/var/lib/mysql
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
services:
postgresql:
image: postgres:16.4
ports:
- "5472:5432"
env_file:
- env.d/postgresql
healthcheck:
test: ["CMD-SHELL", "pg_isready"]
interval: 1s
timeout: 2s
retries: 300
volumes:
- ./data/db/${RICHIE_SITE:?}:/var/lib/postgresql/data
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# This file is empty on purpose!
Loading

0 comments on commit e6e2931

Please sign in to comment.