Commit df0ce494 authored by Christian BUFFIN's avatar Christian BUFFIN
Browse files

Mise en docker de web-DPO

parent 4960ead6
DB_HOST=web-dpo-db
DB_USERNAME=webdpo
DB_PASSWORD=webdpo
DB_APP_NAME=webdpo
DB_TEST_NAME=webdpo_test
TZ=Europe/Paris
# Docker
## Avertissements
### Fichiers envoyés dans les conteneurs docker
L'utilisation avec docker en mode développement implique, pour éviter de polluer l'espace de travail sur le poste du
développeur avec les répertoires `app/tmp`, `vendors` ou `node_modules`, de lister les fichiers à envoyer dans le
conteneur docker dans les fichiers `docker-compose.yml` et `docker/app/Dockerfile`.
Cela ne pose pas de problème pour les fichiers se trouvant dans `app`, mais peut nécessiter des ajustements si des fichiers
sont ajoutés dans d'autres répertoires ou à la racine.
### Patches SQL
Par ailleurs, pour pouvoir passer les fichiers SQL au lancement du docker, il faut penser, si on renomme ou ajoute des
fichiers SQL, à modifier la fonction `init_data_db` du fichier `docker/app/usr/bin/docker-entrypoint.sh`.
### Fichiers importants pour docker
| Fichier / dossier | Git | Commentaire |
| --- | --- | --- |
| `docker/app/Dockerfile` | Nouveau | `Dockerfile` du conteneur applicatif |
| `docker/app/etc/apache2/sites-available/webdpo.conf` | Nouveau | Configuration apache du conteneur applicatif |
| `docker/app/etc/cron.d/web-dpo` | Nouveau | Tâche planifiée du conteneur applicatif |
| `docker/app/usr/bin/composer-install.php` | Nouveau | Script facilitant l'installation de `composer` sur le conteneur applicatif |
| `docker/app/usr/bin/docker-entrypoint.sh` | Nouveau | Script exécuté au lancement du conteneur applicatif, passe les patches SQL, corrige les sources de PHPUnit, création de liens symboliques, modification des permissions et lancement des services (cron, apache) |
| `docker/app/var/www/html/web-dpo/app/Config/database.php` | Nouveau | Configuration de la connexion à la base de données propre au conteneur applicatif |
| `docker/app/var/www/html/web-dpo/app/Config/email.php` | Nouveau | Configuration du serveur de mail propre au conteneur applicatif |
| `docker/postgres/docker-entrypoint-initdb.d/000-init.sql` | Nouveau | Création de l'utilisateur et de la base de données `webdpo` sur le conteneur PostgreSQL |
| `.env` | Nouveau | Variables d'environnement utilisées pour les conteneurs docker |
| `cake_utils.sh` | Nouveau | Lancement de commandes (pre_commit, lint, tests, ...) dans le conteneur applicatif |
| `docker-compose.sh` | Nouveau | Commandes permettant de nettoyer ou de lancer les conteneurs docker nécessaires à web-DPO (voir ci-dessous) |
| `docker-compose.yml` | Nouveau | `docker-compose` des services de `web-DPO` |
| `README-docker.md` | Nouveau | Ce fichier d'information |
## Commandes
### Lancement de web-DPO
```bash
./docker-compose.sh web-dpo
```
### Nettoyage des images docker etc...
Lorsqu'on change de page ou que l'on a fait des modifications importantes, pour supprimer les images docker etc et
repartir sur une installation propre.
```bash
./docker-compose.sh clear
```
### Exécution côté conteneur applicatif
```bash
docker-compose exec web-dpo-app /bin/bash
```
#### Console de vérification de l'application
```bash
sudo -u www-data vendors/bin/cake checks -app app
```
#### Lancement de l'intégration continue manuellement
```bash
./cake_utils.sh pre_commit
```
## Conteneurs Docker
| Application | Container | URL | Identifiant |
| --- | --- | --- | --- |
| __Cloudooo__ | `web-dpo-cloudooo` | | |
| __Golem__ | `web-dpo-golem` | | |
| __Mailcatcher__ | `web-dpo-mailcatcher` | http://localhost:2081/ | |
| __PostgreSQL__ | `web-dpo-db` | | `webdpo` / `webdpo` |
| __web-DPO__ | `web-dpo-app` | http://localhost:2080/ | `superadmin` / `admin` |
Voir le fichier `docker-compose.yml`
#!/usr/bin/env bash
# @todo: reporter dans LS-PKi
# ----------------------------------------------------------------------------------------------------------------------
# "Library"
# ----------------------------------------------------------------------------------------------------------------------
set -o errexit
set -o nounset
set -o pipefail
# Internal constants
declare -r _blue_="\e[34m"
declare -r _cyan_="\e[36m"
declare -r _default_="\e[0m"
declare -r _green_="\e[32m"
declare -r _red_="\e[31m"
# Bootstrap
if [ "`getopt --longoptions xtrace -- x "$@" 2> /dev/null | grep --color=none "\(^\|\s\)\(\-x\|\-\-xtrace\)\($\|\s\)"`" != "" ] ; then
declare -r __XTRACE__=1
set -o xtrace
else
declare -r __XTRACE__=0
fi
declare -r __PID__="${$}"
declare -r __FILE__="$(realpath "${0}")"
declare -r __SCRIPT__="$(basename "${__FILE__}")"
declare -r __ROOT__="$(realpath "$(dirname "${__FILE__}")")"
printf "${_cyan_}Startup:${_default_} started process ${__PID__}\n\n"
# Error and exit handling: exit is trapped, as well as signals.
# If a __cleanup__ function exists, it will be called on signal or exit and the exit code will be passed as parameter.
__trap_signals__()
{
local code="${?}"
if [ ${code} -ne 0 ] ; then
local signal=$((${code} - 128))
local name="`kill -l ${signal}`"
>&2 printf "\nProcess ${__PID__} received SIG${name} (${signal}), exiting..."
fi
}
__trap_exit__()
{
local code="${?}"
if [ ${code} -eq 0 ] ; then
printf "\n${_green_}Success:${_default_} process ${__PID__} exited normally\n"
else
>&2 printf "\n${_red_}Error:${_default_} process ${__PID__} exited with error code ${code}\n"
fi
if [ "`type -t __cleanup__`" = "function" ] ; then
__cleanup__
fi
}
trap "__trap_signals__" SIGHUP SIGINT SIGQUIT SIGTERM
trap "__trap_exit__" EXIT
# ----------------------------------------------------------------------------------------------------------------------
# Custom code
# ----------------------------------------------------------------------------------------------------------------------
__APP__="${__ROOT__}/app"
__PLUGIN__CAKETEST__="${__APP__}/Plugin/CakeTest"
__TMP__="${__APP__}/tmp"
__OUT__="${__TMP__}/out"
# Usage function
__usage__()
{
local internals="app, plugin interne CakeTest, app/Vendor"
printf "NAME\n"
printf " %s\n" "$__SCRIPT__"
printf "\nDESCRIPTION\n"
printf " Commandes courantes pour un projet CakePHP 2.x chez Libriciel SCOP\"\n"
printf "\nSYNOPSIS\n"
printf " %s [OPTION] [COMMAND]\n" "$__SCRIPT__"
printf "\nCOMMANDS\n"
printf " check\t\tVérifie que l'on soit bien à la racine d'un projet CakePHP 2.x\n"
printf " clear\t\tVérifie l'installation (commande check) et nettoie le cache d'un projet CakePHP 2.x\n"
printf " lint_php\tVérification de la syntaxe des fichiers .php, .ctp (${internals})\n"
printf " lint_po\tVérification de la syntaxe des fichiers .po (${internals})\n"
printf " lint_sh\tVérification de la syntaxe des fichiers .sh (bash, ${internals})\n"
printf " lint_sql\tVérification de la syntaxe des fichiers .sql (postgresql, ${internals})\n"
printf " pre_commit\tLint (php, po, sh et sql si pgsanity est installé), tests\n"
printf " tail\t\tTail les fichiers de log de CakePHP 2.x (et les crée si besoin)\n"
printf " tests\t\tNettoie le cache (commande clear) et effectue les tests unitaires\n"
printf "\nOPTIONS\n"
printf " -h\tAffiche cette aide\n"
printf " -x|--xtrace\tMode debug, affiche chaque commande avant de l'exécuter (set -o xtrace)\n"
printf "\nEXEMPLES\n"
printf " %s -h\n" "$__SCRIPT__"
printf " %s clear\n" "$__SCRIPT__"
printf " %s lint_php\n" "$__SCRIPT__"
printf " %s lint_po\n" "$__SCRIPT__"
printf " %s tests\n" "$__SCRIPT__"
printf " %s tests Basics\n" "$__SCRIPT__"
printf " %s tests LibricielChecks Utility/LibricielChecksValidation\n" "$__SCRIPT__"
}
cake2_dir()
{
candidates="lib/Cake \
vendor/cakephp/cakephp/lib/Cake \
vendors/cakephp/cakephp/lib/Cake"
for candidate in $candidates ; do
if [ -d "${candidate}" ] ; then
echo "${candidate}"
return 0
fi
done
>&2 printf "\n${_red_}Error:${_default_} could not find CakePHP's VERSION.txt file (searched in ${candidates})"
return 1
}
cake2_check()
{
echo "Checking for a CakePHP 2.x install"
fileName="`cake2_dir`/VERSION.txt"
if [ ! -f "${fileName}" ] ; then
>&2 printf "${_red_}Error:${_default_} could not find CakePHP's VERSION.txt file (${fileName})"
return 1
else
grep --color=none "^2\.[0-9]\+" $fileName
return $?
fi
}
# Clears temporary files in app/tmp for a CakePHP 2.x install
cake2_clear()
{
local find_cmd="find -L ${__TMP__} -type f ! -name 'empty'"
cake2_check \
&& echo "Clearing the CakePHP 2.x install" \
&& sudo bash -c "( if [ ! -d ${__TMP__} ] ; then mkdir -p ${__TMP__} ; fi )" \
&& nb_target="`sudo bash -c "( ${find_cmd} ) | wc -l"`" \
&& sudo bash -c "( ${find_cmd} -exec rm {} \; )" \
&& nb_remaining="`sudo bash -c "( ${find_cmd} ) | wc -l"`" \
&& nb_done=$((nb_target - nb_remaining))
if [ ${nb_target} -le ${nb_done} ] ; then
printf "${_cyan_}Success:${_default_} ${nb_done} file(s) cleared\n"
else
>&2 printf "${_red_}Error:${_default_} ${nb_done} file(s) cleared out of ${nb_target} (`${find_cmd}`)\n"
fi
dirs="${__TMP__}/cache/models ${__TMP__}/cache/persistent ${__TMP__}/cache/views ${__TMP__}/logs ${__TMP__}/sessions ${__TMP__}/tests"
for dir in $dirs ; do
if [ ! -d "${dir}" ] ; then
mkdir -p "${dir}"
fi
touch "${dir}/empty"
done
return $?
}
tests()
{
local category="${1}"
local file="${2}"
local dest="${__OUT__}/phpunit/${category}"
rm -rf "${dest}" \
&& mkdir -p "${dest}" \
&& touch "${dest}/empty" \
&& chmod -R g+rw,a+rw "${dest}" \
&& "`cake2_dir`/Console/cake" \
test ${category} ${file} \
-app app \
--configuration "${__ROOT__}/phpunit.xml" \
--coverage-clover "${dest}/phpunit.coverage.xml" \
--coverage-html "${dest}/coverage/" \
--debug \
--log-junit "${dest}/phpunit.xml" \
--stderr \
--strict \
--verbose
}
lint_php()
{
local code=0
local return=0
set +o errexit
for file in $(find -L "${__APP__}" -type f \( -name "*.php" -or -name "*.ctp" \) \( -not -path "*/Plugin/*" -or -path "*/Plugin/CakeTest/*" \) -not -path "*/plugins/*" -not -path "*/vendors/*" | sort -t '/') ; do
php -l "${file}"
code=$?
if [ $code -ne 0 ] ; then
return=$code
fi
done
set -o errexit
return $return
}
lint_po()
{
local code=0
local return=0
set +o errexit
for file in $(find -L "${__ROOT__}" -type f -name "*.po" \( -not -path "*/Plugin/*" -or -path "*/Plugin/CakeTest/*" \) -not -path "*/plugins/*" -not -path "*/vendors/*" | sort -t '/') ; do
echo "${file}"
msgfmt -v -c -o /dev/null "${file}"
code=$?
if [ $code -ne 0 ] ; then
return=$code
fi
done
set -o errexit
return $return
}
lint_sh()
{
local code=0
local return=0
set +o errexit
for file in $(find -L "${__ROOT__}" -type f -name "*.sh" \( -not -path "*/Plugin/*" -or -path "*/Plugin/CakeTest/*" \) -not -path "*/plugins/*" -not -path "*/vendors/*" | sort -t '/') ; do
echo "${file}"
/bin/bash -n "${file}"
code=$?
if [ $code -ne 0 ] ; then
return=$code
fi
done
set -o errexit
return $return
}
lint_sql()
{
local code=0
local return=0
which pgsanity > /dev/null 2>&1 || ( >&2 printf "${_red_}Error:${_default_} pgsanity is not installed, fix it with: ${_cyan_}sudo pip install pgsanity${_default_}" ; exit 1 )
set +o errexit
for file in $(find -L "${__APP__}/Config/Schema/CreationBase/" "${__APP__}/Plugin/" -type f -name "*.sql" -not -path "*/Plugin/*" -not -path "*/plugins/*" -not -path "*/vendors/*" | sort -t '/') ; do
echo "${file}"
pgsanity "${file}"
code=$?
if [ $code -ne 0 ] ; then
return=$code
fi
done
set -o errexit
return $return
}
# Create and tail the log files of a CakePHP 2.x install
cake2_tail()
{
local levels="emergency alert critical error warning notice info debug"
cake2_check && \
echo "Preparing to tail logs..."
# @todo filter by user/group (apache|www-data|jenkins)
for level in $levels ; do
local file="app/tmp/logs/${level}.log"
sudo touch "${file}"
sudo chown www-data: "${file}"
done
tail -f app/tmp/logs/*.log
return $?
}
pre_commit()
{
# phpcpd 3.0.1, 2020-04-04 19h11
# Found 39 clones with 1622 duplicated lines in 41 files (3.17% duplicated lines out of 51168 total lines of code.)
set +o errexit
(
cake2_clear \
&& lint_php \
&& lint_sh \
&& lint_po \
&& if [ $( which pgsanity > /dev/null 2>&1 ; echo $? ) -eq 0 ] ; then lint_sql ; fi \
&& tests "app" "AllTests" \
)
code=$?
set -o errexit
if [ $code -ne 0 ] ; then
>&2 echo "Erreur lors des vérifications de pré-commit ($code)"
else
echo "Succès lors des vérifications de pré-commit ($code)"
fi
return $code
}
# ----------------------------------------------------------------------------------------------------------------------
# Main function
# ----------------------------------------------------------------------------------------------------------------------
__main__()
{
(
opts=`getopt --longoptions help,xtrace -- hx "$@"` || ( >&2 __usage__ ; exit 1 )
eval set -- "$opts"
while true ; do
case "$1" in
-h|--help)
__usage__
exit 0
;;
-x|--xtrace)
shift
;;
--)
shift
break
;;
*)
>&2 __usage__
exit 1
;;
esac
done
case "${1:-}" in
bake)
shift
bake "$@"
exit $?
;;
check)
cake2_check
exit $?
;;
clear)
cake2_clear
exit $?
;;
lint_php)
lint_php
exit $?
;;
lint_po)
lint_po
exit $?
;;
lint_sh)
lint_sh
exit $?
;;
lint_sql)
lint_sql
exit $?
;;
pre_commit)
pre_commit
exit $?
;;
tail)
cake2_tail
exit $?
;;
tests)
if [ ! -z "${3:-}" ] ; then
cake2_clear \
&& tests "${2}" "${3}"
elif [ ! -z "${2:-}" ] ; then
cake2_clear \
&& tests "app" "${2}"
else
cake2_clear \
&& tests "app" "AllTests"
fi
exit $?
;;
--)
shift
break
;;
*)
>&2 __usage__
exit 1
;;
esac
exit 0
)
}
__main__ "$@"
#!/usr/bin/env bash
# @todo: reporter dans LS-PKi
CLEAR="0"
# ----------------------------------------------------------------------------------------------------------------------
# "Library"
# ----------------------------------------------------------------------------------------------------------------------
set -o errexit
set -o nounset
set -o pipefail
# Internal constants
declare -r _blue_="\e[34m"
declare -r _cyan_="\e[36m"
declare -r _default_="\e[0m"
declare -r _green_="\e[32m"
declare -r _red_="\e[31m"
# Bootstrap
if [ "`getopt --longoptions xtrace -- x "$@" 2> /dev/null | grep --color=none "\(^\|\s\)\(\-x\|\-\-xtrace\)\($\|\s\)"`" != "" ] ; then
declare -r __XTRACE__=1
set -o xtrace
else
declare -r __XTRACE__=0
fi
declare -r __PID__="${$}"
declare -r __FILE__="$(realpath "${0}")"
declare -r __SCRIPT__="$(basename "${__FILE__}")"
declare -r __ROOT__="$(realpath "$(dirname "${__FILE__}")")"
printf "${_cyan_}Startup:${_default_} started process ${__PID__}\n\n"
# Error and exit handling: exit is trapped, as well as signals.
# If a __cleanup__ function exists, it will be called on signal or exit and the exit code will be passed as parameter.
__trap_signals__()
{
local code="${?}"
if [ ${code} -ne 0 ] ; then
local signal=$((${code} - 128))
local name="`kill -l ${signal}`"
>&2 printf "\nProcess ${__PID__} received SIG${name} (${signal}), exiting..."
fi
}
__trap_exit__()
{
local code="${?}"
if [ ${code} -eq 0 ] ; then
printf "\n${_green_}Success:${_default_} process ${__PID__} exited normally\n"
else
>&2 printf "\n${_red_}Error:${_default_} process ${__PID__} exited with error code ${code}\n"
fi
if [ "`type -t __cleanup__`" = "function" ] ; then
__cleanup__
fi
}
trap "__trap_signals__" SIGHUP SIGINT SIGQUIT SIGTERM
trap "__trap_exit__" EXIT
# ----------------------------------------------------------------------------------------------------------------------
# Custom code
# ----------------------------------------------------------------------------------------------------------------------
COMPOSE_FILE="${__ROOT__}/docker-compose.yml"
IMAGE_NAMES="web-dpo-app web-dpo-cloudooo web-dpo-db web-dpo-golem web-dpo-mailcatcher"
PROJECT_NAME="web-dpo"
__usage__()
{
printf "NAME\n"
printf " %s\n" "${__SCRIPT__}"
printf "\nDESCRIPTION\n"
printf " Commandes courantes docker-compose pour le projet web-DPO\n"
printf "\nSYNOPSIS\n"
printf " %s [OPTION] [COMMAND]\n" "${__SCRIPT__}"
printf "\nCOMMANDS\n"
printf " clear\t\tSupprime les images docker de web-DPO\n"
printf " web-dpo\tDémarrage de web-DPO\n"
printf "\nOPTIONS\n"
printf " -c|--clear\tSupprime les images docker de web-DPO avant de les reconstruire\n"
printf " -h|--help\tAffiche cette aide\n"
printf " -x|--xtrace\tMode debug, affiche chaque commande avant de l'exécuter (set -o xtrace)\n"
printf "\nEXEMPLES\n"
printf " %s -h\n" "${__SCRIPT__}"
printf " %s clear\n" "${__SCRIPT__}"
printf " %s --clear web-dpo\n" "${__SCRIPT__}"
}
__clear_images__()
{
if [ "$CLEAR" -eq "1" ]
then
docker image rmi -f ${IMAGE_NAMES} > /dev/null 2>&1 \
&& docker image prune -f
fi
return ${?}
}
__web_dpo__()
{
( \
__clear_images__ \
&& docker-compose -f "${COMPOSE_FILE}" --project-name ${PROJECT_NAME} down -v --remove-orphans \
&& docker-compose -f "${COMPOSE_FILE}" --project-name ${PROJECT_NAME} up \
&& docker-compose -f "${COMPOSE_FILE}" --project-name ${PROJECT_NAME} down -v --remove-orphans \
)
EXIT_STATUS=${?}
if [ ${EXIT_STATUS} -ne 0 ]
then
echo >&2 "Erreur(s) lors du lancement du docker web-DPO (exit ${EXIT_STATUS})"
fi
return ${EXIT_STATUS}
}