From a6d8196d7c97618595d318e5f9927f6ac74a3c42 Mon Sep 17 00:00:00 2001 From: Kieren Evans Date: Fri, 30 Oct 2020 16:54:38 +0200 Subject: [PATCH] publish 'spryker' harness --- LICENSE | 13 + _twig/docker-compose.yml/application.yml.twig | 1 + .../service/blackfire.yml.twig | 10 + .../service/chrome.yml.twig | 7 + .../docker-compose.yml/service/cron.yml.twig | 22 + .../service/elasticsearch.yml.twig | 14 + .../service/memcached.yml.twig | 6 + .../docker-compose.yml/service/mysql.yml.twig | 19 + .../service/php-fpm-exporter.yml.twig | 12 + .../service/php-fpm.yml.twig | 35 ++ .../service/postgres.yml.twig | 14 + .../service/rabbitmq.yml.twig | 16 + .../service/redis-session.yml.twig | 8 + .../docker-compose.yml/service/redis.yml.twig | 8 + .../docker-compose.yml/service/relay.yml.twig | 9 + .../docker-compose.yml/service/solr.yml.twig | 38 ++ .../service/tideways.yml.twig | 10 + .../service/varnish.yml.twig | 49 ++ .../service/webapp.yml.twig | 3 + application/overlay/.dockerignore.twig | 8 + application/overlay/Jenkinsfile.twig | 95 ++++ .../overlay/_twig/.dockerignore/dynamic.twig | 2 + .../overlay/_twig/.dockerignore/static.twig | 1 + application/overlay/auth.json.twig | 15 + application/skeleton/README.md.twig | 244 ++++++++++ docker-compose.yml.twig | 43 ++ docker-sync.yml.twig | 16 + docker/image/console/.dockerignore | 1 + docker/image/console/Dockerfile.twig | 51 +++ docker/image/console/root/app/.gitkeep | 0 docker/image/console/root/bin/app | 19 + .../image/console/root/entrypoint.dynamic.sh | 54 +++ docker/image/console/root/entrypoint.sh.twig | 51 +++ .../console/root/home/build/.my.cnf.twig | 4 + docker/image/console/root/lib/functions.sh | 21 + docker/image/console/root/lib/sidekick.sh | 124 +++++ .../console/root/lib/task/assets/apply.sh | 38 ++ .../console/root/lib/task/assets/dump.sh | 24 + docker/image/console/root/lib/task/build.sh | 13 + .../root/lib/task/build/backend.sh.twig | 15 + .../root/lib/task/build/frontend.sh.twig | 15 + .../root/lib/task/composer/install.sh.twig | 16 + .../root/lib/task/database/available.sh | 31 ++ .../root/lib/task/database/import.sh.twig | 10 + .../image/console/root/lib/task/http/wait.sh | 19 + .../image/console/root/lib/task/init.sh.twig | 18 + .../console/root/lib/task/install.sh.twig | 11 + .../console/root/lib/task/migrate.sh.twig | 10 + .../console/root/lib/task/overlay/apply.sh | 6 + docker/image/console/root/lib/task/phpstan.sh | 25 + .../root/lib/task/rabbitmq/vhosts.sh.twig | 15 + .../console/root/lib/task/skeleton/apply.sh | 6 + docker/image/console/root/lib/task/state.sh | 8 + .../console/root/usr/local/bin/send_mail | 5 + .../conf.d/docker-php-ext-blackfire.ini.twig | 8 + .../conf.d/docker-php-ext-tideways.ini.twig | 8 + .../php/conf.d/docker-php-ext-xdebug.ini.twig | 8 + .../root/usr/local/etc/php/php.ini.twig | 10 + docker/image/cron/Dockerfile.twig | 37 ++ docker/image/cron/root/cron-run-with-env.sh | 5 + docker/image/cron/root/crontab.twig | 3 + docker/image/cron/root/entrypoint.sh.twig | 56 +++ docker/image/nginx/Dockerfile.twig | 17 + .../root/etc/nginx/conf.d/0-nginx.conf.twig | 3 + .../nginx/conf.d/default.conf.template.twig | 68 +++ .../root/etc/nginx/snippets/certificate.conf | 2 + .../root/etc/nginx/snippets/ssl-params.conf | 17 + .../nginx/root/etc/ssl/certs/app.crt.twig | 1 + .../nginx/root/etc/ssl/private/app.key.twig | 1 + docker/image/php-fpm/.dockerignore | 1 + docker/image/php-fpm/Dockerfile.twig | 37 ++ docker/image/php-fpm/root/app/.gitkeep | 0 .../image/php-fpm/root/entrypoint.dynamic.sh | 69 +++ docker/image/php-fpm/root/entrypoint.sh.twig | 30 ++ .../etc/supervisor/conf.d/container-cmd.conf | 9 + .../root/etc/supervisor/supervisord.conf | 18 + .../php-fpm/root/fix_app_permissions.sh.twig | 55 +++ .../php-fpm/root/usr/local/bin/send_mail | 5 + .../etc/php-fpm.d/pool.conf.template.twig | 24 + .../conf.d/docker-php-ext-blackfire.ini.twig | 8 + .../conf.d/docker-php-ext-tideways.ini.twig | 8 + .../php/conf.d/docker-php-ext-xdebug.ini.twig | 8 + .../root/usr/local/etc/php/php.ini.twig | 10 + docker/image/relay/Dockerfile | 2 + docker/image/relay/root/etc/nginx/nginx.conf | 24 + docker/image/solr4/Dockerfile | 37 ++ docker/image/tls-offload/Dockerfile | 2 + .../root/etc/nginx/conf.d/0-nginx.conf.twig | 3 + .../root/etc/nginx/conf.d/default.conf.twig | 47 ++ .../root/etc/nginx/snippets/certificate.conf | 2 + .../root/etc/nginx/snippets/ssl-params.conf | 17 + .../root/etc/ssl/certs/app.crt.twig | 1 + .../root/etc/ssl/private/app.key.twig | 1 + .../varnish/root/etc/varnish/default.vcl.twig | 41 ++ docs/.gitkeep | 0 harness/attributes/common.yml | 433 ++++++++++++++++++ harness/attributes/docker-base.yml | 286 ++++++++++++ harness/config/commands.yml | 329 +++++++++++++ harness/config/docker-sync.yml | 8 + harness/config/events.yml | 15 + harness/config/external-images.yml | 38 ++ harness/config/functions.yml | 209 +++++++++ harness/config/mutagen.yml | 103 +++++ harness/config/pipeline.yml | 120 +++++ harness/config/secrets.yml | 125 +++++ harness/scripts/destroy.sh | 19 + harness/scripts/disable.sh | 9 + harness/scripts/docker_sync.sh | 84 ++++ harness/scripts/enable.sh.twig | 85 ++++ harness/scripts/latest-mutagen-release.php | 33 ++ harness/scripts/mutagen.sh | 112 +++++ helm/app/Chart.yaml.twig | 5 + .../service/varnish/configmap.yaml.twig | 17 + helm/app/_twig/values.yaml/resources.yml.twig | 3 + helm/app/templates/_base_helper.tpl | 47 ++ helm/app/templates/application/app-init.yaml | 64 +++ .../templates/application/app-migrate.yaml | 62 +++ .../application/console/deployment.yaml | 71 +++ .../templates/application/console/secret.yaml | 2 + .../application/cron/deployment.yaml | 82 ++++ .../templates/application/cron/secret.yaml | 2 + .../application/image-pull-config.yaml | 25 + .../application/webapp/deployment.yaml | 160 +++++++ .../application/webapp/podmonitor.yaml | 19 + .../application/webapp/secret-nginx.yaml | 1 + .../application/webapp/secret-php-fpm.yaml | 2 + .../templates/application/webapp/service.yaml | 17 + .../service/elasticsearch/deployment.yaml | 62 +++ .../templates/service/elasticsearch/pvc.yaml | 31 ++ .../service/elasticsearch/service.yaml | 17 + .../templates/service/mysql/deployment.yaml | 73 +++ helm/app/templates/service/mysql/pvc.yaml | 31 ++ helm/app/templates/service/mysql/secret.yaml | 1 + helm/app/templates/service/mysql/service.yaml | 17 + .../service/postgres/deployment.yaml | 65 +++ helm/app/templates/service/postgres/pvc.yaml | 31 ++ .../templates/service/postgres/secret.yaml | 1 + .../templates/service/postgres/service.yaml | 17 + .../service/rabbitmq/deployment.yaml | 66 +++ helm/app/templates/service/rabbitmq/pvc.yaml | 31 ++ .../templates/service/rabbitmq/secret.yaml | 1 + .../templates/service/rabbitmq/service.yaml | 20 + .../service/redis-session/deployment.yaml | 70 +++ .../templates/service/redis-session/pvc.yaml | 31 ++ .../service/redis-session/service.yaml | 17 + .../templates/service/redis/deployment.yaml | 71 +++ helm/app/templates/service/redis/pvc.yaml | 31 ++ helm/app/templates/service/redis/service.yaml | 17 + .../service/tideways/deployment.yaml | 41 ++ .../templates/service/tideways/service.yaml | 17 + .../service/varnish/headless-service.yaml | 18 + .../templates/service/varnish/service.yaml | 17 + .../service/varnish/statefulset.yaml | 56 +++ helm/app/values-preview.yaml.twig | 11 + helm/app/values-production.yaml.twig | 14 + helm/qa/Chart.yaml.twig | 5 + helm/qa/requirements.yaml.twig | 4 + mutagen.yml.twig | 30 ++ 158 files changed, 5532 insertions(+) create mode 100644 LICENSE create mode 100644 _twig/docker-compose.yml/application.yml.twig create mode 100644 _twig/docker-compose.yml/service/blackfire.yml.twig create mode 100644 _twig/docker-compose.yml/service/chrome.yml.twig create mode 100644 _twig/docker-compose.yml/service/cron.yml.twig create mode 100644 _twig/docker-compose.yml/service/elasticsearch.yml.twig create mode 100644 _twig/docker-compose.yml/service/memcached.yml.twig create mode 100644 _twig/docker-compose.yml/service/mysql.yml.twig create mode 100644 _twig/docker-compose.yml/service/php-fpm-exporter.yml.twig create mode 100644 _twig/docker-compose.yml/service/php-fpm.yml.twig create mode 100644 _twig/docker-compose.yml/service/postgres.yml.twig create mode 100644 _twig/docker-compose.yml/service/rabbitmq.yml.twig create mode 100644 _twig/docker-compose.yml/service/redis-session.yml.twig create mode 100644 _twig/docker-compose.yml/service/redis.yml.twig create mode 100644 _twig/docker-compose.yml/service/relay.yml.twig create mode 100644 _twig/docker-compose.yml/service/solr.yml.twig create mode 100644 _twig/docker-compose.yml/service/tideways.yml.twig create mode 100644 _twig/docker-compose.yml/service/varnish.yml.twig create mode 100644 _twig/docker-compose.yml/service/webapp.yml.twig create mode 100644 application/overlay/.dockerignore.twig create mode 100644 application/overlay/Jenkinsfile.twig create mode 100644 application/overlay/_twig/.dockerignore/dynamic.twig create mode 100644 application/overlay/_twig/.dockerignore/static.twig create mode 100644 application/overlay/auth.json.twig create mode 100644 application/skeleton/README.md.twig create mode 100644 docker-compose.yml.twig create mode 100644 docker-sync.yml.twig create mode 100644 docker/image/console/.dockerignore create mode 100644 docker/image/console/Dockerfile.twig create mode 100644 docker/image/console/root/app/.gitkeep create mode 100755 docker/image/console/root/bin/app create mode 100755 docker/image/console/root/entrypoint.dynamic.sh create mode 100755 docker/image/console/root/entrypoint.sh.twig create mode 100644 docker/image/console/root/home/build/.my.cnf.twig create mode 100644 docker/image/console/root/lib/functions.sh create mode 100644 docker/image/console/root/lib/sidekick.sh create mode 100644 docker/image/console/root/lib/task/assets/apply.sh create mode 100644 docker/image/console/root/lib/task/assets/dump.sh create mode 100644 docker/image/console/root/lib/task/build.sh create mode 100644 docker/image/console/root/lib/task/build/backend.sh.twig create mode 100644 docker/image/console/root/lib/task/build/frontend.sh.twig create mode 100644 docker/image/console/root/lib/task/composer/install.sh.twig create mode 100644 docker/image/console/root/lib/task/database/available.sh create mode 100644 docker/image/console/root/lib/task/database/import.sh.twig create mode 100644 docker/image/console/root/lib/task/http/wait.sh create mode 100644 docker/image/console/root/lib/task/init.sh.twig create mode 100644 docker/image/console/root/lib/task/install.sh.twig create mode 100644 docker/image/console/root/lib/task/migrate.sh.twig create mode 100644 docker/image/console/root/lib/task/overlay/apply.sh create mode 100644 docker/image/console/root/lib/task/phpstan.sh create mode 100644 docker/image/console/root/lib/task/rabbitmq/vhosts.sh.twig create mode 100644 docker/image/console/root/lib/task/skeleton/apply.sh create mode 100644 docker/image/console/root/lib/task/state.sh create mode 100755 docker/image/console/root/usr/local/bin/send_mail create mode 100644 docker/image/console/root/usr/local/etc/php/conf.d/docker-php-ext-blackfire.ini.twig create mode 100644 docker/image/console/root/usr/local/etc/php/conf.d/docker-php-ext-tideways.ini.twig create mode 100644 docker/image/console/root/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini.twig create mode 100644 docker/image/console/root/usr/local/etc/php/php.ini.twig create mode 100644 docker/image/cron/Dockerfile.twig create mode 100755 docker/image/cron/root/cron-run-with-env.sh create mode 100644 docker/image/cron/root/crontab.twig create mode 100644 docker/image/cron/root/entrypoint.sh.twig create mode 100644 docker/image/nginx/Dockerfile.twig create mode 100644 docker/image/nginx/root/etc/nginx/conf.d/0-nginx.conf.twig create mode 100644 docker/image/nginx/root/etc/nginx/conf.d/default.conf.template.twig create mode 100644 docker/image/nginx/root/etc/nginx/snippets/certificate.conf create mode 100644 docker/image/nginx/root/etc/nginx/snippets/ssl-params.conf create mode 100644 docker/image/nginx/root/etc/ssl/certs/app.crt.twig create mode 100644 docker/image/nginx/root/etc/ssl/private/app.key.twig create mode 100644 docker/image/php-fpm/.dockerignore create mode 100644 docker/image/php-fpm/Dockerfile.twig create mode 100644 docker/image/php-fpm/root/app/.gitkeep create mode 100755 docker/image/php-fpm/root/entrypoint.dynamic.sh create mode 100755 docker/image/php-fpm/root/entrypoint.sh.twig create mode 100644 docker/image/php-fpm/root/etc/supervisor/conf.d/container-cmd.conf create mode 100644 docker/image/php-fpm/root/etc/supervisor/supervisord.conf create mode 100755 docker/image/php-fpm/root/fix_app_permissions.sh.twig create mode 100755 docker/image/php-fpm/root/usr/local/bin/send_mail create mode 100644 docker/image/php-fpm/root/usr/local/etc/php-fpm.d/pool.conf.template.twig create mode 100644 docker/image/php-fpm/root/usr/local/etc/php/conf.d/docker-php-ext-blackfire.ini.twig create mode 100644 docker/image/php-fpm/root/usr/local/etc/php/conf.d/docker-php-ext-tideways.ini.twig create mode 100644 docker/image/php-fpm/root/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini.twig create mode 100644 docker/image/php-fpm/root/usr/local/etc/php/php.ini.twig create mode 100644 docker/image/relay/Dockerfile create mode 100644 docker/image/relay/root/etc/nginx/nginx.conf create mode 100644 docker/image/solr4/Dockerfile create mode 100644 docker/image/tls-offload/Dockerfile create mode 100644 docker/image/tls-offload/root/etc/nginx/conf.d/0-nginx.conf.twig create mode 100644 docker/image/tls-offload/root/etc/nginx/conf.d/default.conf.twig create mode 100644 docker/image/tls-offload/root/etc/nginx/snippets/certificate.conf create mode 100644 docker/image/tls-offload/root/etc/nginx/snippets/ssl-params.conf create mode 100644 docker/image/tls-offload/root/etc/ssl/certs/app.crt.twig create mode 100644 docker/image/tls-offload/root/etc/ssl/private/app.key.twig create mode 100644 docker/image/varnish/root/etc/varnish/default.vcl.twig create mode 100644 docs/.gitkeep create mode 100644 harness/attributes/common.yml create mode 100644 harness/attributes/docker-base.yml create mode 100644 harness/config/commands.yml create mode 100644 harness/config/docker-sync.yml create mode 100644 harness/config/events.yml create mode 100644 harness/config/external-images.yml create mode 100644 harness/config/functions.yml create mode 100644 harness/config/mutagen.yml create mode 100644 harness/config/pipeline.yml create mode 100644 harness/config/secrets.yml create mode 100755 harness/scripts/destroy.sh create mode 100755 harness/scripts/disable.sh create mode 100644 harness/scripts/docker_sync.sh create mode 100755 harness/scripts/enable.sh.twig create mode 100644 harness/scripts/latest-mutagen-release.php create mode 100644 harness/scripts/mutagen.sh create mode 100644 helm/app/Chart.yaml.twig create mode 100644 helm/app/_twig/templates/service/varnish/configmap.yaml.twig create mode 100644 helm/app/_twig/values.yaml/resources.yml.twig create mode 100644 helm/app/templates/_base_helper.tpl create mode 100644 helm/app/templates/application/app-init.yaml create mode 100644 helm/app/templates/application/app-migrate.yaml create mode 100644 helm/app/templates/application/console/deployment.yaml create mode 100644 helm/app/templates/application/console/secret.yaml create mode 100644 helm/app/templates/application/cron/deployment.yaml create mode 100644 helm/app/templates/application/cron/secret.yaml create mode 100644 helm/app/templates/application/image-pull-config.yaml create mode 100644 helm/app/templates/application/webapp/deployment.yaml create mode 100644 helm/app/templates/application/webapp/podmonitor.yaml create mode 100644 helm/app/templates/application/webapp/secret-nginx.yaml create mode 100644 helm/app/templates/application/webapp/secret-php-fpm.yaml create mode 100644 helm/app/templates/application/webapp/service.yaml create mode 100644 helm/app/templates/service/elasticsearch/deployment.yaml create mode 100644 helm/app/templates/service/elasticsearch/pvc.yaml create mode 100644 helm/app/templates/service/elasticsearch/service.yaml create mode 100644 helm/app/templates/service/mysql/deployment.yaml create mode 100644 helm/app/templates/service/mysql/pvc.yaml create mode 100644 helm/app/templates/service/mysql/secret.yaml create mode 100644 helm/app/templates/service/mysql/service.yaml create mode 100644 helm/app/templates/service/postgres/deployment.yaml create mode 100644 helm/app/templates/service/postgres/pvc.yaml create mode 100644 helm/app/templates/service/postgres/secret.yaml create mode 100644 helm/app/templates/service/postgres/service.yaml create mode 100644 helm/app/templates/service/rabbitmq/deployment.yaml create mode 100644 helm/app/templates/service/rabbitmq/pvc.yaml create mode 100644 helm/app/templates/service/rabbitmq/secret.yaml create mode 100644 helm/app/templates/service/rabbitmq/service.yaml create mode 100644 helm/app/templates/service/redis-session/deployment.yaml create mode 100644 helm/app/templates/service/redis-session/pvc.yaml create mode 100644 helm/app/templates/service/redis-session/service.yaml create mode 100644 helm/app/templates/service/redis/deployment.yaml create mode 100644 helm/app/templates/service/redis/pvc.yaml create mode 100644 helm/app/templates/service/redis/service.yaml create mode 100644 helm/app/templates/service/tideways/deployment.yaml create mode 100644 helm/app/templates/service/tideways/service.yaml create mode 100644 helm/app/templates/service/varnish/headless-service.yaml create mode 100644 helm/app/templates/service/varnish/service.yaml create mode 100644 helm/app/templates/service/varnish/statefulset.yaml create mode 100644 helm/app/values-preview.yaml.twig create mode 100644 helm/app/values-production.yaml.twig create mode 100644 helm/qa/Chart.yaml.twig create mode 100644 helm/qa/requirements.yaml.twig create mode 100644 mutagen.yml.twig diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..7aa45c22 --- /dev/null +++ b/LICENSE @@ -0,0 +1,13 @@ +Copyright 2020, Inviqa + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/_twig/docker-compose.yml/application.yml.twig b/_twig/docker-compose.yml/application.yml.twig new file mode 100644 index 00000000..0a8a086d --- /dev/null +++ b/_twig/docker-compose.yml/application.yml.twig @@ -0,0 +1 @@ +# deprecated, please define/override individual services in _twig/docker-compose.yml/service/*.yaml diff --git a/_twig/docker-compose.yml/service/blackfire.yml.twig b/_twig/docker-compose.yml/service/blackfire.yml.twig new file mode 100644 index 00000000..6cf45a9d --- /dev/null +++ b/_twig/docker-compose.yml/service/blackfire.yml.twig @@ -0,0 +1,10 @@ + blackfire: + image: {{ @('services.blackfire.image') }} + labels: + - traefik.enable=false + environment: {{ to_nice_yaml(deep_merge([ + @('services.blackfire.environment'), + @('services.blackfire.environment_secrets') + ]), 2, 6) | raw }} + networks: + - private diff --git a/_twig/docker-compose.yml/service/chrome.yml.twig b/_twig/docker-compose.yml/service/chrome.yml.twig new file mode 100644 index 00000000..c8a1c813 --- /dev/null +++ b/_twig/docker-compose.yml/service/chrome.yml.twig @@ -0,0 +1,7 @@ + chrome: + image: yukinying/chrome-headless-browser:latest + command: ["--no-sandbox", "--disable-gpu", "--headless", "--disable-dev-shm-usage", "--remote-debugging-address=0.0.0.0", "--remote-debugging-port=9222", "--user-data-dir=/data"] + labels: + - traefik.enable=false + networks: + - private diff --git a/_twig/docker-compose.yml/service/cron.yml.twig b/_twig/docker-compose.yml/service/cron.yml.twig new file mode 100644 index 00000000..f41ceb6b --- /dev/null +++ b/_twig/docker-compose.yml/service/cron.yml.twig @@ -0,0 +1,22 @@ + cron: + build: + context: ./ + dockerfile: .my127ws/docker/image/cron/Dockerfile +{% if @('app.build') == 'dynamic' %} + volumes: + - {{ (syncvolume) ? @('workspace.name') ~ '-sync:/app:nocopy' : ('./:/app' ~ @('docker.compose.host_volume_options')) }} + - ./.my127ws/application:/home/build/application +{% else %} + image: {{ @('services.cron.image') }} +{% endif %} + environment: {{ to_nice_yaml(deep_merge([ + @('services.php-base.environment'), + @('services.cron.environment'), + @('services.php-base.environment_secrets'), + @('services.cron.environment_secrets') + ]), 2, 6) | raw }} +{% include blocks ~ 'environment.yml.twig' %} + networks: + - private + labels: + - traefik.enable=false diff --git a/_twig/docker-compose.yml/service/elasticsearch.yml.twig b/_twig/docker-compose.yml/service/elasticsearch.yml.twig new file mode 100644 index 00000000..486384f7 --- /dev/null +++ b/_twig/docker-compose.yml/service/elasticsearch.yml.twig @@ -0,0 +1,14 @@ + elasticsearch: + image: {{ @('services.elasticsearch.image') }} + labels: + - traefik.enable=false + environment: + ES_JAVA_OPTS: -Xms512m -Xmx512m + discovery.type: single-node + networks: + - private +{% if @('app.build') != 'static' and @('docker.port_forward.enabled') %} + ports: + - "127.0.0.1:0:9200" + - "127.0.0.1:0:9300" +{% endif %} diff --git a/_twig/docker-compose.yml/service/memcached.yml.twig b/_twig/docker-compose.yml/service/memcached.yml.twig new file mode 100644 index 00000000..f5aaa50a --- /dev/null +++ b/_twig/docker-compose.yml/service/memcached.yml.twig @@ -0,0 +1,6 @@ + memcached: + image: {{ @('services.memcached.image') }} + labels: + - traefik.enable=false + networks: + - private diff --git a/_twig/docker-compose.yml/service/mysql.yml.twig b/_twig/docker-compose.yml/service/mysql.yml.twig new file mode 100644 index 00000000..5ffe5da5 --- /dev/null +++ b/_twig/docker-compose.yml/service/mysql.yml.twig @@ -0,0 +1,19 @@ +{% set command = @('services.mysql.options') + | filter(v => v is not empty) + | map((value, var) => '--' ~ var ~ '=' ~ value) + | reduce((carry, v) => carry|merge([v]), []) %} + mysql: + image: {{ @('services.mysql.image') }} + labels: + - traefik.enable=false + command: {{ to_nice_yaml(command, 2, 6) }} + environment: {{ to_nice_yaml(deep_merge([ + @('services.mysql.environment'), + @('services.mysql.environment_secrets') + ]), 2, 6) | raw }} + networks: + - private +{% if @('app.build') != 'static' and @('docker.port_forward.enabled') %} + ports: + - "127.0.0.1:{{ @('database.port_forward') ? @('database.port_forward') : '0' }}:3306" +{% endif %} diff --git a/_twig/docker-compose.yml/service/php-fpm-exporter.yml.twig b/_twig/docker-compose.yml/service/php-fpm-exporter.yml.twig new file mode 100644 index 00000000..dcd7115d --- /dev/null +++ b/_twig/docker-compose.yml/service/php-fpm-exporter.yml.twig @@ -0,0 +1,12 @@ + php-fpm-exporter: + image: {{ @('services.php-fpm-exporter.image') }} + environment: {{ to_nice_yaml(deep_merge([ + @('services.php-fpm-exporter.environment'), + @('services.php-fpm-exporter.environment_secrets') + ]), 2, 6) | raw }} + labels: + - traefik.enable=false + depends_on: + - php-fpm + networks: + - private diff --git a/_twig/docker-compose.yml/service/php-fpm.yml.twig b/_twig/docker-compose.yml/service/php-fpm.yml.twig new file mode 100644 index 00000000..53ad5a5a --- /dev/null +++ b/_twig/docker-compose.yml/service/php-fpm.yml.twig @@ -0,0 +1,35 @@ +{% set blocks = '_twig/docker-compose.yml/' %} +{% set syncvolume = false %} +{% if @('host.os') == 'darwin' and @('docker-sync') == 'yes' %} +{% set syncvolume = true %} +{% elseif @('host.os') == 'darwin' and @('mutagen') == 'yes' %} +{% set syncvolume = true %} +{% endif %} + + php-fpm: + build: .my127ws/docker/image/php-fpm +{% if @('app.build') == 'dynamic' %} +{% if @('services.cron.enabled') %} + image: {{ @('workspace.name') ~ '-php-fpm:dev' }} +{% endif %} + volumes: + - {{ (syncvolume) ? @('workspace.name') ~ '-sync:/app:nocopy' : ('./:/app' ~ @('docker.compose.host_volume_options')) }} + - ./.my127ws:/.my127ws +{% else %} + image: {{ @('services.php-fpm.image') }} +{% endif %} + labels: + - traefik.enable=false + networks: + - private + environment: {{ to_nice_yaml(deep_merge([ + @('services.php-base.environment'), + @('services.php-fpm.environment'), + @('services.php-base.environment_secrets'), + @('services.php-fpm.environment_secrets') + ]), 2, 6) | raw }} +{% include blocks ~ 'environment.yml.twig' %} + expose: +{% for pool in @('php-fpm.pools') %} + - {{ pool.port }} +{% endfor %} diff --git a/_twig/docker-compose.yml/service/postgres.yml.twig b/_twig/docker-compose.yml/service/postgres.yml.twig new file mode 100644 index 00000000..924d5fba --- /dev/null +++ b/_twig/docker-compose.yml/service/postgres.yml.twig @@ -0,0 +1,14 @@ + postgres: + image: {{ @('services.postgres.image') }} + labels: + - traefik.enable=false + environment: {{ to_nice_yaml(deep_merge([ + @('services.postgres.environment'), + @('services.postgres.environment_secrets') + ]), 2, 6) | raw }} + networks: + - private +{% if @('app.build') != 'static' and @('docker.port_forward.enabled') %} + ports: + - "127.0.0.1:{{ @('database.port_forward') ? @('database.port_forward') : '0' }}:5432" +{% endif %} diff --git a/_twig/docker-compose.yml/service/rabbitmq.yml.twig b/_twig/docker-compose.yml/service/rabbitmq.yml.twig new file mode 100644 index 00000000..d905ffe7 --- /dev/null +++ b/_twig/docker-compose.yml/service/rabbitmq.yml.twig @@ -0,0 +1,16 @@ + rabbitmq: + image: {{ @('services.rabbitmq.image') }} + environment: {{ to_nice_yaml(deep_merge([ + @('services.rabbitmq.environment'), + @('services.rabbitmq.environment_secrets') + ]), 2, 6) | raw }} + networks: + - private + - shared + labels: + - traefik.backend={{ @('rabbitmq.host') }}-{{ @('workspace.name') }} + - traefik.frontend.rule=Host:{{ @('rabbitmq.external_host') }} + - traefik.docker.network=my127ws + - traefik.port={{ @('rabbitmq.api_port') }} + - co.elastic.logs/module=rabbitmq + - co.elastic.metrics/module=rabbitmq diff --git a/_twig/docker-compose.yml/service/redis-session.yml.twig b/_twig/docker-compose.yml/service/redis-session.yml.twig new file mode 100644 index 00000000..77b14d67 --- /dev/null +++ b/_twig/docker-compose.yml/service/redis-session.yml.twig @@ -0,0 +1,8 @@ + redis-session: + image: {{ @('services.redis_session.image') }} + # 1GB; evict key that would expire soonest + command: redis-server --maxmemory 1073742000 --maxmemory-policy volatile-ttl --save 3600 1 --save 300 100 --save 60 10000 + labels: + - traefik.enable=false + networks: + - private diff --git a/_twig/docker-compose.yml/service/redis.yml.twig b/_twig/docker-compose.yml/service/redis.yml.twig new file mode 100644 index 00000000..8f4c9816 --- /dev/null +++ b/_twig/docker-compose.yml/service/redis.yml.twig @@ -0,0 +1,8 @@ + redis: + image: {{ @('services.redis.image') }} + # 1GB; evict any least recently used key even if they don't have a TTL + command: redis-server --maxmemory 1073742000 --maxmemory-policy allkeys-lru --save 3600 1 --save 300 100 --save 60 10000 + labels: + - traefik.enable=false + networks: + - private diff --git a/_twig/docker-compose.yml/service/relay.yml.twig b/_twig/docker-compose.yml/service/relay.yml.twig new file mode 100644 index 00000000..d91a1140 --- /dev/null +++ b/_twig/docker-compose.yml/service/relay.yml.twig @@ -0,0 +1,9 @@ + relay: + build: .my127ws/docker/image/relay + labels: + - traefik.enable=false + networks: + private: + aliases: + - mailhog-relay + shared: {} diff --git a/_twig/docker-compose.yml/service/solr.yml.twig b/_twig/docker-compose.yml/service/solr.yml.twig new file mode 100644 index 00000000..030f415f --- /dev/null +++ b/_twig/docker-compose.yml/service/solr.yml.twig @@ -0,0 +1,38 @@ + solr: +{% if @('services.solr.major_version') == 4 %} + build: + context: .my127ws/docker/image/solr4/ +{% else %} + image: {{ @('services.solr.image') }} +{% endif %} + environment: {{ to_nice_yaml(deep_merge([ + @('services.solr.environment'), + @('services.solr.environment_secrets') + ]), 2, 6) | raw }} + labels: + - traefik.backend=solr-{{ @('workspace.name') }} + - traefik.frontend.rule=Host:solr-{{ @('hostname') }} + - traefik.docker.network=my127ws + - traefik.port=8983 + command: + - solr-precreate + - {{ @('services.solr.environment.SOLR_CORE_NAME') }} +{% if @('services.solr.config_path') %} + - /opt/solr/server/solr/configsets/{{ @('services.solr.environment.SOLR_CORE_NAME') }} +{% elseif @('services.solr.major_version') == 4 %} + - /opt/solr/example/example-schemaless/solr/{{ @('services.solr.environment.SOLR_CORE_NAME') }} +{% endif %} + volumes: +{% if @('services.solr.config_path') %} + - {{ @('services.solr.config_path')}}:/opt/solr/server/solr/configsets/{{ @('services.solr.environment.SOLR_CORE_NAME') }}/conf +{% endif %} +{% if @('services.solr.major_version') == 4 %} + - solr_data:/opt/solr/example/solr +{% elseif @('services.solr.major_version') < 8 %} + - solr_data:/opt/solr/server/solr/mycores +{% else %} + - solr_data:/var/solr +{% endif %} + networks: + - private + - shared diff --git a/_twig/docker-compose.yml/service/tideways.yml.twig b/_twig/docker-compose.yml/service/tideways.yml.twig new file mode 100644 index 00000000..1a077781 --- /dev/null +++ b/_twig/docker-compose.yml/service/tideways.yml.twig @@ -0,0 +1,10 @@ + tideways: + image: {{ @('services.tideways.image') }} + labels: + - traefik.enable=false + environment: {{ to_nice_yaml(deep_merge([ + @('services.tideways.environment'), + @('services.tideways.environment_secrets') + ]), 2, 6) | raw }} + networks: + - private diff --git a/_twig/docker-compose.yml/service/varnish.yml.twig b/_twig/docker-compose.yml/service/varnish.yml.twig new file mode 100644 index 00000000..c185f389 --- /dev/null +++ b/_twig/docker-compose.yml/service/varnish.yml.twig @@ -0,0 +1,49 @@ +{% if @('services.varnish.enabled') %} +{% set hostnames = [@('hostname')] %} +{% set hostnames = hostnames|merge(@('hostname_aliases')|map(alias => "#{alias}." ~ @('domain'))) %} + varnish: + image: {{ @('services.varnish.image') }} + labels: + - traefik.backend={{ @('workspace.name') }} + - traefik.frontend.rule=Host:{{ hostnames|join(',') }} + - traefik.docker.network=my127ws + - traefik.port=80 + environment: {{ to_nice_yaml(deep_merge([ + @('services.varnish.environment'), + @('services.varnish.environment_secrets') + ]), 2, 6) | raw }} + links: + - nginx:nginx + volumes: + - .my127ws/docker/image/varnish/root/etc/varnish/default.vcl:/etc/varnish/default.vcl:ro + - type: tmpfs + target: /var/lib/varnish:exec + tmpfs: + size: "100000" + networks: + private: + aliases: + - varnish-0.varnish-headless +{% if @('replicas.varnish') > 1 %} +{% for instanceNumber in 1..(@('replicas.varnish')-1) %} + - varnish-{{ instanceNumber }}.varnish-headless +{% endfor %} +{% endif %} + shared: {} + + # Provide TLS offloading for integration tests via varnish + tls-offload: + build: + context: .my127ws/docker/image/tls-offload/ + labels: + - traefik.enable=false + links: + - varnish:varnish + networks: + private: + aliases: +{% for alias in hostnames %} + - {{ alias }} +{% endfor %} + shared: {} +{% endif %} diff --git a/_twig/docker-compose.yml/service/webapp.yml.twig b/_twig/docker-compose.yml/service/webapp.yml.twig new file mode 100644 index 00000000..c88f9448 --- /dev/null +++ b/_twig/docker-compose.yml/service/webapp.yml.twig @@ -0,0 +1,3 @@ +{% set blocks = '_twig/docker-compose.yml/' %} +{% include blocks ~ 'service/nginx.yml.twig' %} +{% include blocks ~ 'service/php-fpm.yml.twig' %} diff --git a/application/overlay/.dockerignore.twig b/application/overlay/.dockerignore.twig new file mode 100644 index 00000000..96c90adc --- /dev/null +++ b/application/overlay/.dockerignore.twig @@ -0,0 +1,8 @@ +{% set build = @('app.build') %} +{% set blocks = 'application/overlay/_twig/.dockerignore/' %} + +{% if build == 'dynamic' %} +{% include blocks ~ 'dynamic.twig' %} +{% else %} +{% include blocks ~ 'static.twig' %} +{% endif %} diff --git a/application/overlay/Jenkinsfile.twig b/application/overlay/Jenkinsfile.twig new file mode 100644 index 00000000..3b34dc3d --- /dev/null +++ b/application/overlay/Jenkinsfile.twig @@ -0,0 +1,95 @@ +pipeline { + agent { label "my127ws" } + environment { + MY127WS_KEY = credentials('{{ @('jenkins.credentials.my127ws_key') }}') + MY127WS_ENV = "pipeline" + } + triggers { cron(env.BRANCH_NAME == '{{ @('git.default_branch') }}' ? 'H H(0-6) * * *' : '') } + stages { + stage('Build') { + steps { + sh 'ws install' + milestone(10) + } + } + stage('Checks without development dependencies') { + steps { + sh 'ws exec composer test-production-quality' + sh 'ws exec app composer:development_dependencies' + milestone(20) + } + } + stage('Test') { + parallel { + stage('quality') { steps { sh 'ws exec composer test-quality' } } + stage('unit') { steps { sh 'ws exec composer test-unit' } } + stage('acceptance') { steps { sh 'ws exec composer test-acceptance' } } + stage('helm kubeval qa') { steps { sh 'ws helm kubeval qa' } } + } + } +{% if @('pipeline.publish.enabled') == 'yes' %} + stage('Publish') { +{% if @('pipeline.publish.environment') %} + environment { +{% for key, value in @('pipeline.publish.environment') %} + {{ key }} = {{ value }} +{% endfor %} + } +{% endif %} + when { + not { triggeredBy 'TimerTrigger' } + anyOf { +{% for branch in @('pipeline.publish.branches') %} + branch '{{ branch }}' +{% endfor %} +{% if @('pipeline.qa.enabled') == 'yes' %} + branch '{{ @('pipeline.qa.branch') }}' +{% endif %} +{% if @('pipeline.preview.enabled') == 'yes' %} +{% for branch in @('pipeline.preview.target_branches') %} + changeRequest target: '{{ branch }}' +{% endfor %} +{% endif %} + } + } + steps { + milestone(50) + sh 'ws app publish' +{% if @('pipeline.publish.chart.enabled') %} + lock(resource: '{{ @('pipeline.publish.chart.git.repository') }}', inversePrecedence: true) { + sh 'ws app publish chart "${GIT_BRANCH}" "{{ @('workspace.name') }} build artifact ${GIT_COMMIT}"' + } +{% endif %} + } + } +{% endif %} +{% if @('pipeline.qa.enabled') == 'yes' %} + stage('Deploy (QA)') { +{% if @('pipeline.qa.environment') %} + environment { +{% for key, value in @('pipeline.qa.environment') %} + {{ key }} = {{ value }} +{% endfor %} + } +{% endif %} + when { + not { triggeredBy 'TimerTrigger' } + branch '{{ @('pipeline.qa.branch') }}' + } + steps { + milestone(100) + lock(resource: '{{ @('workspace.name') }}-qa-deploy', inversePrecedence: true) { + milestone(101) + sh 'ws app deploy qa' + } + } + } +{% endif %} + } + post { + always { + sh 'ws destroy' + cleanWs() + } + } +} diff --git a/application/overlay/_twig/.dockerignore/dynamic.twig b/application/overlay/_twig/.dockerignore/dynamic.twig new file mode 100644 index 00000000..4ebb7d2c --- /dev/null +++ b/application/overlay/_twig/.dockerignore/dynamic.twig @@ -0,0 +1,2 @@ +* +!.my127ws diff --git a/application/overlay/_twig/.dockerignore/static.twig b/application/overlay/_twig/.dockerignore/static.twig new file mode 100644 index 00000000..c007eac9 --- /dev/null +++ b/application/overlay/_twig/.dockerignore/static.twig @@ -0,0 +1 @@ +# no need for exclusions for now diff --git a/application/overlay/auth.json.twig b/application/overlay/auth.json.twig new file mode 100644 index 00000000..0731d871 --- /dev/null +++ b/application/overlay/auth.json.twig @@ -0,0 +1,15 @@ +{ + "http-basic": { + {% for repo in @('composer.auth.basic') %} + "{{ repo.path }}": { + "username": "{{ repo.username }}", + "password": "{{ repo.password }}" + }{% if not loop.last %},{% endif %} + {% endfor %} + }, + "github-oauth": { + {% if @('composer.auth.github') %} + "github.com": "{{ @('composer.auth.github') }}" + {% endif %} + } +} diff --git a/application/skeleton/README.md.twig b/application/skeleton/README.md.twig new file mode 100644 index 00000000..8d6526bc --- /dev/null +++ b/application/skeleton/README.md.twig @@ -0,0 +1,244 @@ +{% set blocks = 'application/skeleton/_twig/README.md/' %} +# {{ @('workspace.name') }} + +Please follow the below steps to get started, if you encounter any issues installing the dependencies or provisioning the development environment, please check the [Common Issues](#common-issues) section first. + +## Development Environment + +### Getting Started + +#### Prerequisites + +##### General + +- Access to LastPass folders + - `Shared-{{ @('workspace.name') }}-Servers` and `Shared-{{ @('workspace.name') }}-Accounts` + +##### Docker + +- A working Docker setup + - On MacOS, use [Docker Desktop for Mac](https://docs.docker.com/docker-for-mac/install/). + - On Linux, add the official Docker repository described under the "Server" section on [Install Docker Engine](https://docs.docker.com/engine/install/) and install the "docker-ce" package. + You will also need to have a recent [docker-compose](https://docs.docker.com/compose/install/) version - at least `1.26.0`. + +#### Setup + +1. Install [workspace](https://github.com/my127/workspace) +2. Copy the LastPass entry "{{ @('workspace.name') }}: Development Environment Key" to a new blank file named `workspace.override.yml` in the project root. +3. Run `ws install` + +{% if not @('yves.external_hosts') -%} +Once installed, the site should be available at [https://{{ @('hostname') }}](https://{{ @('hostname') }}). +{% set additional_hostnames = @('hostname_aliases')|map(alias => "#{alias}." ~ @('domain')) %} +{% if additional_hostnames %} + +**Additional sites**: +{% for host in additional_hostnames -%} +- [https://{{ host }}](https://{{ host }}) +{% endfor -%} +{% endif -%} +{% else -%} +Once installed, the site should be available at the following URLs: + +**Yves**: +{% for store, yves_external_host in @('yves.external_hosts') -%} +- {{ store }} Store: [https://{{ yves_external_host }}](https://{{ yves_external_host }}) +{% endfor %} + +**Zed**: +{% for store, zed_external_host in @('zed.external_hosts') -%} +- {{ store }} Zed: [https://{{ zed_external_host }}](https://{{ zed_external_host }}) +{% endfor %} +{% endif %} + +**Additional services**: +- Mailhog: [https://mail.my127.site](https://mail.my127.site) +{% if @('services.rabbitmq.enabled') -%} +- RabbitMQ: [https://{{ @('rabbitmq.external_host') }}](https://{{ @('rabbitmq.external_host') }}) +{% endif -%} +{% if @('services.jenkins.enabled') -%} +- Jenkins: [https://{{ @('jenkins.external_host') }}](https://{{ @('jenkins.external_host') }}) +{% endif %} +{% if @('services.solr.enabled') -%} +- Solr: [https://solr-{{ @('hostname') }}/solr/](https://solr-{{ @('hostname') }}/solr/) +{% endif -%} + +### Development environment cleanup + +To stop the development environment, run `ws disable`. + +To start the development environment again, run `ws enable`. + +To remove the development environment, run `ws destroy`. + +### Frontend + +The frontend build should be automatically done as part of bringing up the environment. + +To trigger a rebuild, run `ws frontend build`. + +To watch for changes, run `ws frontend watch`. + +To gain access to the `console` container where the builds happen: `ws frontend console`. + +### Harness Version Updates + +If you have been notified that a harness version upgrade is available by your team, do the following. + +If you have an existing environment running: +```bash +ws harness update existing +``` + +or if you don't have one running right now or would like to set up from fresh: +```bash +ws harness update fresh +``` + +{% for readme_block in @('framework.readme_blocks') %} +{% include blocks ~ readme_block ~ '.md.twig' %} +{% endfor %} + +{% if @('services.mysql.enabled') -%} +### MySQL Access + +MySQL can be used either via command line tools via `ws db console` or via GUI tools. + +In your GUI tool, set up a new connection to localhost with the port being the returned port number from: +```bash +ws port mysql +``` + +{% if @('database.port_forward') == "" -%} +This port will change each time the project environment is started, as docker will allocate a random unused port +on your host machine. + +To set a consistent port for this project, choose a port number that you think will be unique across all projects +that your developers will encounter (e.g. not 3306!). Acceptable range of ports is 1-65535. + +Once you have a port number, you can define it in the workspace.yml with: +```yaml +attribute('database.port_forward'): portNumberHere +``` +{%- endif %} + +The connection username and password is listed under the `mysql` service environment section in `docker-compose.yml` in +the project root. +{% endif %} + +### Xdebug + +Xdebug is turned off by default as it drastically slows down requests for all developers. + +To enable, run `ws feature xdebug on`. To turn off again, `ws feature xdebug off`. + +To enable on CLI in `ws console`, run `ws feature xdebug cli on`. To turn off again, `ws feature xdebug cli off`. + +Xdebug is set up to listen to your computer's 9000 port once enabled, so all you would need to do in your IDE is: +1. Create a mapping from the project root to `/app` for name `workspace`, hostname `localhost` and port 80. +2. Depending on the IDE, you may have to configure the settings for the IDE to have idekey being `workspace`. + Some IDEs also need to restart after changing this. Not required for PhpStorm. +3. Listen for connections. +4. If trying to debug a website, configure the IDE key of browser Xdebug extension such as one listed on + [Browser Debugging Extensions](https://www.jetbrains.com/help/phpstorm/browser-debugging-extensions.html) + to be `workspace`, toggle debug on, then refresh the page in the browser +5. If trying to debug a CLI application, re-run the CLI command. Some CLI programs like phpstan explicitly turn + off Xdebug deliberately, but provide a `--xdebug` flag to allow running with Xdebug. + +[Here's a good guide for PhpStorm](https://www.jetbrains.com/help/phpstorm/zero-configuration-debugging.html). + +If you have trouble with triggered requests not starting connections to your IDE, check that +`sudo lsof -i :9000 | grep LISTEN` on your host shows process from your IDE. +If it doesn't, stop the indicated process (e.g. `php-fpm`) and toggle the Xdebug listen button off and on again in PhpStorm. + +### Performance on macOS + +Page load times with Docker for Mac can vary considerably due to the sharing of files from the macOS disk to the small +virtual machine that docker is running inside. +This is especially so when there is a large quantity of small files, such as with a large composer node_modules or +vendor folder. + +[Mutagen](https://mutagen.io/documentation/transports/docker) and +[docker-sync](https://github.com/EugenMayer/docker-sync/) are tools to synchronise files between host machine and +docker containers. +They both enable production-like performance at the cost of having to synchronise files with an intermediate +"data" container. + +{% if @('mutagen') == 'yes' %} +Mutagen is enabled on the development environment. +You can switch to docker-sync if you wish with `ws switch docker-sync`. +{% elseif @('docker-sync') == 'yes' %} +docker-sync is enabled on the development environment. +You can switch to mutagen if you wish with `ws switch mutagen`. +{% else %} +If it takes over 2 seconds to load a page, you should consider enabling mutagen or docker-sync by adding the following +to `workspace.override.yml` in the project root, or after testing it and the whole team would like to use it, +`workspace.yml` in the project root: + +```yaml +# for mutagen: +attribute('docker-sync'): 'no' +attribute('mutagen'): 'yes' +# or for docker-sync: +attribute('docker-sync'): 'yes' +attribute('mutagen'): 'no' +``` + +Then running `ws harness prepare && ws disable && ws enable`. +The initial sync can take between 5 to 15 minutes, depending on the size of the project directory. + +If committing the attribute changes to `workspace.yml`, ensure the `Performance on macOS` section from +`.my127ws/application/skeleton/README.md` is copied to the project's README.md too! +{% endif %} + +The following are some useful commands regarding Mutagen: +```bash +# To check the Mutagen sync status (sync is ready when status is "Watching for changes") +mutagen monitor +# To debug a sync error +mutagen list +``` +{% if @('docker-sync') == 'yes' %} + +Useful commands for docker-sync: +```bash +# Check the logs +docker-sync logs -f +``` +{% endif %} + +### Common Issues + +As setup issues are encountered please detail with step by step fix instructions, and where possible update the project or the upstream workspace harness itself to provide a more permanent fix. + +* If you get a error that the TLS certificate has expired for the development website in your browser: + * Restart the my127 global traefik proxy with `ws global service proxy restart`. + This will fetch new TLS certificates for `*.my127.site`. +* If you use mutagen and operations such as `mutagen project pause` during `ws disable` are hanging: + * Head to Docker Desktop Preferences via the system tray icon + * Turn off "Enable cloud experience" under the Command Line area of Preferences + * Click the "Apply and restart" button +* If you use docker-sync and notice that your changes aren't synchronising to the environment: + * Check if your file exists with your changes in `ws console` + * If your file in `ws console` has changed okay, check your project for any caching that + would prevent changes to source code appearing immediately. + * If the file changes do not appear in `ws console` reasonably quickly, it might be that + Docker for Mac is overwhelmed with file change events. + * Restarting Docker for Mac using the system tray icon's menu and then running `ws enable` again + will fix it. + +# License + +Copyright 2020, Inviqa + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/docker-compose.yml.twig b/docker-compose.yml.twig new file mode 100644 index 00000000..9bc2760f --- /dev/null +++ b/docker-compose.yml.twig @@ -0,0 +1,43 @@ +{% set blocks = '_twig/docker-compose.yml/' %} +{% set syncvolume = false %} +{% if @('host.os') == 'darwin' and @('docker-sync') == 'yes' %} +{% set syncvolume = true %} +{% elseif @('host.os') == 'darwin' and @('mutagen') == 'yes' %} +{% set syncvolume = true %} +{% endif %} +version: '{{ @('docker.compose.file_version') }}' +services: +{% include blocks ~ 'application.yml.twig' %} +{% for serviceName, service in @('services') %} +{% if service['enabled'] %} +{% include blocks ~ 'service/' ~ serviceName ~ '.yml.twig' %} +{% endif %} +{% endfor %} +{% for service in @('app.services') %} +{% if @('services')[service] is not defined or @('services')[service].enabled is not defined %} +{% include blocks ~ 'service/' ~ service ~ '.yml.twig' %} +{% endif %} +{% endfor %} +networks: + private: + external: false + shared: + external: + name: my127ws +{% if syncvolume or @('services.solr.enabled') %} +volumes: +{% if syncvolume %} +{% if @('mutagen') == 'yes' %} +{% for volumeName in get_mutagen_volume_names() %} + {{ volumeName }}: + external: true +{% endfor %} +{% else %} + {{ @('workspace.name') }}-sync: + external: true +{% endif %} +{% endif %} +{% if @('services.solr.enabled') %} + solr_data: +{% endif %} +{% endif %} diff --git a/docker-sync.yml.twig b/docker-sync.yml.twig new file mode 100644 index 00000000..9510ee5a --- /dev/null +++ b/docker-sync.yml.twig @@ -0,0 +1,16 @@ +version: '2' +options: + compose-file-path: + - docker-compose.yml + project_root: config_path +syncs: + {{ @('workspace.name') }}-sync: + src: ./ + sync_userid: '1000' + sync_excludes_type: BelowPath + sync_excludes: &IGNORE + - .docker-sync + - .idea + - .git + - var + watch_excludes: *IGNORE diff --git a/docker/image/console/.dockerignore b/docker/image/console/.dockerignore new file mode 100644 index 00000000..cf49d54d --- /dev/null +++ b/docker/image/console/.dockerignore @@ -0,0 +1 @@ +**/*.twig diff --git a/docker/image/console/Dockerfile.twig b/docker/image/console/Dockerfile.twig new file mode 100644 index 00000000..5b5f1820 --- /dev/null +++ b/docker/image/console/Dockerfile.twig @@ -0,0 +1,51 @@ +FROM {{ @('docker.image.console') }} +# fix upstream signal +STOPSIGNAL SIGTERM + +{% for service in [@('services.redis'), @('services.redis_session')] | filter(v => v.enabled) | slice(0, 1) %} +# copy the redis-cli from the first enabled redis service image +COPY --from={{ service.image }} /usr/local/bin/redis-cli /usr/local/bin/redis-cli +{% endfor %} + +COPY .my127ws/docker/image/console/root / +RUN chown -R build:build /home/build \ + && curl --fail --silent --location --output /sbin/tini https://github.com/krallin/tini/releases/download/v0.19.0/tini \ + && chmod +x /sbin/tini \ + && curl --fail --silent --location --output /usr/local/bin/mhsendmail https://github.com/mailhog/mhsendmail/releases/download/v0.2.0/mhsendmail_linux_amd64 \ + && chmod +x /usr/local/bin/mhsendmail +{%- set install_extensions=@('php.install_extensions')|merge(@('php.cli.install_extensions'))|filter(v => v is not empty) %} +{%- if install_extensions %} \ + && cd /root/installer \ + && ./enable.sh \ + {{ install_extensions|join(" \\\n ") }} +{% endif %} + +ENV APP_MODE={{ @('app.mode') }} \ + APP_BUILD={{ @('app.build') }} \ + ASSETS_DIR={{ @('assets.local') }} + +{% if @('node.version') is not null %} +USER build +RUN . /home/build/.nvm/nvm.sh \ + && nvm install {{ @('node.version') }} \ + && nvm use {{ @('node.version') }} \ + && nvm alias default {{ @('node.version') }} \ + && npm install -g yarn +USER root +{% endif %} + +{% if @('app.build') == 'static' %} +RUN chown build:build /app +COPY --chown=build:build .my127ws/application /home/build/application +COPY --chown=build:build ./ /app +USER build +RUN app build +USER root +{% else %} +VOLUME /app +VOLUME /home/build/application +{% endif %} + +RUN chmod +x /entrypoint.sh +ENTRYPOINT ["/entrypoint.sh"] +CMD ["sleep", "infinity"] diff --git a/docker/image/console/root/app/.gitkeep b/docker/image/console/root/app/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/docker/image/console/root/bin/app b/docker/image/console/root/bin/app new file mode 100755 index 00000000..73a86614 --- /dev/null +++ b/docker/image/console/root/bin/app @@ -0,0 +1,19 @@ +#!/bin/bash +set -e + +main() +{ + task "$@" +} + +bootstrap() +{ + export NVM_DIR="$HOME/.nvm" + # shellcheck source=/home/build/nvm.sh + [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" + . /lib/sidekick.sh + . /lib/functions.sh +} + +bootstrap +main "$@" diff --git a/docker/image/console/root/entrypoint.dynamic.sh b/docker/image/console/root/entrypoint.dynamic.sh new file mode 100755 index 00000000..43bc1a05 --- /dev/null +++ b/docker/image/console/root/entrypoint.dynamic.sh @@ -0,0 +1,54 @@ +#!/bin/bash + +setup_app_volume_permissions() +{ + case "$STRATEGY" in + "host-linux-normal") + usermod -u "$(stat -c '%u' /app)" build + groupmod -g "$(stat -c '%g' /app)" build + ;; + "host-osx-normal") + usermod -u 1000 build + groupmod -g 1000 build + ;; + "host-osx-dockersync") + usermod -u 1000 build + groupmod -g 1000 build + ;; + *) + exit 1 + esac + + chown build:build /app +} + +resolve_volume_mount_strategy() +{ + if [ "${HOST_OS_FAMILY}" = "linux" ]; then + STRATEGY="host-linux-normal" + elif [ "${HOST_OS_FAMILY}" = "darwin" ]; then + if (mount | grep "/app type fuse.osxfs") > /dev/null 2>&1; then + STRATEGY="host-osx-normal" + elif (mount | grep "/app type fuse.grpcfuse") > /dev/null 2>&1; then + STRATEGY="host-osx-normal" + elif (mount | grep "/app type ext4") > /dev/null 2>&1; then + STRATEGY="host-osx-dockersync" + elif (mount | grep "/app type btrfs") > /dev/null 2>&1; then + STRATEGY="host-linux-normal" + else + exit 1 + fi + else + exit 1 + fi +} + +bootstrap() +{ + resolve_volume_mount_strategy + setup_app_volume_permissions +} + +bootstrap + +source /entrypoint.sh "$@" diff --git a/docker/image/console/root/entrypoint.sh.twig b/docker/image/console/root/entrypoint.sh.twig new file mode 100755 index 00000000..e5a291da --- /dev/null +++ b/docker/image/console/root/entrypoint.sh.twig @@ -0,0 +1,51 @@ +#!/bin/bash + +setup_app_networking() +{ + # make linux consistent with docker-for-mac + if [ "${HOST_OS_FAMILY}" = "linux" ]; then + DOCKER_INTERNAL_HOST="host.docker.internal" + if ! grep $DOCKER_INTERNAL_HOST /etc/hosts > /dev/null ; then + DOCKER_INTERNAL_IP=$(/sbin/ip route|awk '/default/ { print $3 }') + echo -e "$DOCKER_INTERNAL_IP $DOCKER_INTERNAL_HOST" | tee -a /etc/hosts > /dev/null + fi + fi +} + +run_steps() +{ + # run any command required to be executed at docker startup + {% for step in @('php.entrypoint.steps') -%} + {{ step|raw }} + {% else -%} + : + {% endfor %} + {% for step in @('console.entrypoint.steps') -%} + {{ step|raw }} + {% else -%} + : + {% endfor %} + + # Clean up Tideways module loading if it's meant to be turned off + if [ -n "$TIDEWAYS_ENABLED" ] && [ -f /usr/local/etc/php/conf.d/docker-php-ext-tideways.ini ]; then + if [ "$TIDEWAYS_ENABLED" = "true" ]; then + sed -i'' "s#tideways.connection=.*$#tideways.connection=tcp://$TIDEWAYS_HOST:9135#" /usr/local/etc/php/conf.d/docker-php-ext-tideways.ini + else + rm /usr/local/etc/php/conf.d/docker-php-ext-tideways.ini + fi + fi +} + +bootstrap() +{ + setup_app_networking + run_steps +} + +bootstrap + +if [ "${1:-}" == "sleep" ]; then + exec /sbin/tini -- bash -c "$(printf "%q " "$@")" +else + exec /sbin/tini -- "$@" +fi diff --git a/docker/image/console/root/home/build/.my.cnf.twig b/docker/image/console/root/home/build/.my.cnf.twig new file mode 100644 index 00000000..ef83bda0 --- /dev/null +++ b/docker/image/console/root/home/build/.my.cnf.twig @@ -0,0 +1,4 @@ +[client] +host=mysql +user=root +password={{ @('database.root_pass') }} diff --git a/docker/image/console/root/lib/functions.sh b/docker/image/console/root/lib/functions.sh new file mode 100644 index 00000000..4b7b4018 --- /dev/null +++ b/docker/image/console/root/lib/functions.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +function db_hasSchema() +{ + if [ "${DB_PLATFORM}" == "mysql" ]; then + SQL="SELECT IF (COUNT(*) = 0, 'no', 'yes') FROM information_schema.tables WHERE table_schema = '$DB_NAME';" + IS_DATABASE_APPLIED="$(mysql -ss -h "$DB_HOST" -u "$DB_USER" -p"$DB_PASS" -e "$SQL")" + elif [ "${DB_PLATFORM}" == "postgres" ]; then + SQL="SELECT CASE WHEN COUNT(*) = 0 THEN 'no' ELSE 'yes' END FROM information_schema.tables WHERE table_catalog = '$DB_NAME' and table_schema='public';" + IS_DATABASE_APPLIED="$(PGPASSWORD="$DB_PASS" psql -qtAX -h "$DB_HOST" -U "$DB_USER" -c "$SQL")" + elif [ -n "${DB_PLATFORM}" ]; then + (>&2 echo "invalid database type") + exit 1 + fi + + if [ -n "${DB_PLATFORM}" ] && [ "$IS_DATABASE_APPLIED" = "no" ]; then + return 1 + fi + + return 0 +} diff --git a/docker/image/console/root/lib/sidekick.sh b/docker/image/console/root/lib/sidekick.sh new file mode 100644 index 00000000..9b364371 --- /dev/null +++ b/docker/image/console/root/lib/sidekick.sh @@ -0,0 +1,124 @@ +#!/bin/bash + +VERBOSE="no" + +RUN_CWD="" + +INDICATOR_RUNNING="34m" +INDICATOR_SUCCESS="32m" +INDICATOR_ERROR="31m" +INDICATOR_PASSTHRU="37m" + +TASKS="/lib/task" + +task() +{ + local TASK_FILE="${TASKS}/${1//:/\/}.sh" + local TASK_NAME="task_${1//:/_}" + + # shellcheck source=/dev/null + declare -F "${TASK_NAME}" &>/dev/null || source "${TASK_FILE}" + + shift + + "${TASK_NAME}" "$@" +} + +prompt() +{ + if [ "${RUN_CWD}" != "$(pwd)" ]; then + RUN_CWD="$(pwd)" + echo -e "\\033[1m[\\033[0mdocker(console):$(pwd)\\033[1m]:\\033[0m" >&2 + fi +} + +run() +{ + local -r COMMAND_DEPRECATED="$*" + local COMMAND=("$@") + local DEPRECATED_MODE=no + + if [[ "${COMMAND[0]}" = *" "* ]]; then + # echo "deprecated: support for passing multiple arguments in the following line will be removed in a future version" >&2 + # echo "run '${COMMAND_DEPRECATED[*]}'" >&2 + # echo "a future major version will only support:" >&2 + # echo "run ${COMMAND_DEPRECATED[*]}" >&2 + # echo >&2 + DEPRECATED_MODE=yes + fi + + if [ "$VERBOSE" = "no" ]; then + + prompt + if [ "${DEPRECATED_MODE}" = "yes" ]; then + echo " > ${COMMAND_DEPRECATED[*]}" >&2 + COMMAND=(bash -e -c "${COMMAND_DEPRECATED[@]}") + else + echo " >$(printf ' %q' "${COMMAND[@]}")" >&2 + fi + + setCommandIndicator "${INDICATOR_RUNNING}" + + if "${COMMAND[@]}" > /tmp/my127ws-stdout.txt 2> /tmp/my127ws-stderr.txt; then + setCommandIndicator "${INDICATOR_SUCCESS}" + else + setCommandIndicator "${INDICATOR_ERROR}" + if [ "${APP_BUILD}" = "static" ]; then + echo "Command failed. stdout:" + cat /tmp/my127ws-stdout.txt + echo + echo "stderr:" + cat /tmp/my127ws-stderr.txt + echo + else + echo "Command failed. stderr:" + cat /tmp/my127ws-stderr.txt + echo "----------------------------------" + echo "Full logs are accessible in the console container at path :-" + echo " stdout: /tmp/my127ws-stdout.txt" + echo " stderr: /tmp/my127ws-stderr.txt" + fi + + return 1 + fi + elif [ "${DEPRECATED_MODE}" = "yes" ]; then + passthru "${COMMAND_DEPRECATED[@]}" + else + passthru "${COMMAND[@]}" + fi +} + +passthru() +{ + local -r COMMAND_DEPRECATED="$*" + local -r COMMAND=("$@") + local DEPRECATED_MODE=no + + if [[ "${COMMAND[0]}" = *" "* ]]; then + # echo "deprecated: support for passing multiple arguments in the following line will be removed in a future version" >&2 + # echo "passthru '${COMMAND_DEPRECATED[*]}'" >&2 + # echo "a future major version will only support:" >&2 + # echo "passthru ${COMMAND_DEPRECATED[*]}" >&2 + # echo >&2 + DEPRECATED_MODE=yes + fi + + prompt + + if [ "${DEPRECATED_MODE}" = "yes" ]; then + echo -e "\\033[${INDICATOR_PASSTHRU}■\\033[0m > $*" >&2 + bash -e -c "${COMMAND_DEPRECATED[@]}" + else + echo -e "\\033[${INDICATOR_PASSTHRU}■\\033[0m >$(printf ' %q' "${COMMAND[@]}")" >&2 + "${COMMAND[@]}" + fi +} + +setCommandIndicator() +{ + echo -ne "\\033[1A" >&2 + echo -ne "\\033[$1" >&2 + echo -n "■" >&2 + echo -ne "\\033[0m" >&2 + echo -ne "\\033[1E" >&2 +} diff --git a/docker/image/console/root/lib/task/assets/apply.sh b/docker/image/console/root/lib/task/assets/apply.sh new file mode 100644 index 00000000..1e543421 --- /dev/null +++ b/docker/image/console/root/lib/task/assets/apply.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +function task_assets_apply() +{ + local ASSETS_DIR="${ASSETS_DIR:-tools/assets/development}" + local IMPORT_COMMAND=() + local PRE_COMMAND=() + + if [ "${DB_PLATFORM}" == "mysql" ]; then + IMPORT_COMMAND=(mysql -h "$DB_HOST" -u "${DB_ADMIN_USER:-$DB_USER}" "-p${DB_ROOT_PASS:-${DB_ADMIN_PASS:-$DB_PASS}}" "$DB_NAME") + elif [ "${DB_PLATFORM}" == "postgres" ]; then + PRE_COMMAND=("PGPASSWORD=$DB_PASS") + IMPORT_COMMAND=(psql -h "$DB_HOST" -U "$DB_USER" "$DB_NAME") + elif [ -n "${DB_PLATFORM}" ]; then + (>&2 echo "invalid database type") + exit 1 + fi + + if ! db_hasSchema; then + + local DATABASE_FILE="/app/${ASSETS_DIR}/${DB_NAME}.sql.gz" + + if [ ! -f "$DATABASE_FILE" ]; then + DATABASE_FILE="$(find "/app/${ASSETS_DIR}/" -maxdepth 1 -name "${DB_NAME}*.sql.gz" -print | head -n1)" + fi + + if [ -f "$DATABASE_FILE" ]; then + "${PRE_COMMAND[@]}" passthru "pv --force '$DATABASE_FILE' | zcat - | $(printf ' %q' "${IMPORT_COMMAND[@]}")" + else + task install + fi + fi + + for file in "/app/${ASSETS_DIR}/"*.files.{tgz,tar.gz}; do + [ -f "$file" ] || continue + run tar -xvf "${file}" -C /app + done +} diff --git a/docker/image/console/root/lib/task/assets/dump.sh b/docker/image/console/root/lib/task/assets/dump.sh new file mode 100644 index 00000000..817a67a5 --- /dev/null +++ b/docker/image/console/root/lib/task/assets/dump.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +function task_assets_dump() +{ + local ASSETS_DIR="${ASSETS_DIR:-tools/assets/development}" + local DUMP_COMMAND=() + local PRE_COMMAND=() + + if [ ! -d "/app/${ASSETS_DIR}" ]; then + run mkdir -p "/app/${ASSETS_DIR}" + fi + + if [ "${DB_PLATFORM}" == "mysql" ]; then + DUMP_COMMAND=(mysqldump -h "${DB_HOST}" -u "${DB_USER}" "-p${DB_PASS}" "${DB_NAME}") + elif [ "${DB_PLATFORM}" == "postgres" ]; then + PRE_COMMAND=("PGPASSWORD=$DB_PASS") + DUMP_COMMAND=(pg_dump -h "${DB_HOST}" -U "${DB_USER}" "${DB_NAME}") + elif [ -n "${DB_PLATFORM}" ]; then + (>&2 echo "invalid database type") + exit 1 + fi + + "${PRE_COMMAND[@]}" run "$(printf ' %q' "${DUMP_COMMAND[@]}") | gzip > '/app/${ASSETS_DIR}/${DB_NAME}.sql.gz'" +} diff --git a/docker/image/console/root/lib/task/build.sh b/docker/image/console/root/lib/task/build.sh new file mode 100644 index 00000000..c49bf57e --- /dev/null +++ b/docker/image/console/root/lib/task/build.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +function task_build() +{ + if [ ! -f /app/composer.json ]; then + task skeleton:apply + fi + + task overlay:apply + + task build:backend + task build:frontend +} diff --git a/docker/image/console/root/lib/task/build/backend.sh.twig b/docker/image/console/root/lib/task/build/backend.sh.twig new file mode 100644 index 00000000..418fa623 --- /dev/null +++ b/docker/image/console/root/lib/task/build/backend.sh.twig @@ -0,0 +1,15 @@ +#!/bin/bash + +function task_build_backend() +{( + cd {{ @('backend.path') }} + + if [ ! {{ @('backend.build.when')|raw }} ]; then + return 0; + fi + + {% for step in @('backend.build.steps') -%} + {{ step|raw }} + {% endfor %} + +)} diff --git a/docker/image/console/root/lib/task/build/frontend.sh.twig b/docker/image/console/root/lib/task/build/frontend.sh.twig new file mode 100644 index 00000000..deff49a4 --- /dev/null +++ b/docker/image/console/root/lib/task/build/frontend.sh.twig @@ -0,0 +1,15 @@ +#!/bin/bash + +function task_build_frontend() +{( + cd {{ @('frontend.path') }} + + if [ ! {{ @('frontend.build.when')|raw }} ]; then + return 0; + fi + + {% for step in @('frontend.build.steps') -%} + {{ step|raw }} + {% endfor %} + +)} diff --git a/docker/image/console/root/lib/task/composer/install.sh.twig b/docker/image/console/root/lib/task/composer/install.sh.twig new file mode 100644 index 00000000..f321a9d5 --- /dev/null +++ b/docker/image/console/root/lib/task/composer/install.sh.twig @@ -0,0 +1,16 @@ +#!/bin/bash + +function task_composer_install() +{ + {% if @('app.mode') == 'development' and @('app.build') == 'static' %} + passthru composer install --no-interaction --optimize-autoloader + {% elseif @('app.mode') == 'development' %} + passthru composer install --no-interaction + {% else %} + passthru composer install --no-interaction --no-dev --optimize-autoloader + {% endif %} + + {% if @('app.build') == 'static' %} + run "composer clear-cache" + {% endif %} +} diff --git a/docker/image/console/root/lib/task/database/available.sh b/docker/image/console/root/lib/task/database/available.sh new file mode 100644 index 00000000..c39b848c --- /dev/null +++ b/docker/image/console/root/lib/task/database/available.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +function task_database_available() +{ + local command="" + + if [ "${DB_PLATFORM}" == "mysql" ]; then + command="mysqladmin -h $DB_HOST -u ${DB_ADMIN_USER:-$DB_USER} -p${DB_ROOT_PASS:-${DB_ADMIN_PASS:-$DB_PASS}} ping --connect_timeout=10" + elif [ "${DB_PLATFORM}" == "postgres" ]; then + command="pg_isready -h $DB_HOST" + elif [ "${DB_PLATFORM}" == "" ]; then + # no database is used + return + else + (>&2 echo "invalid database type") + exit 1 + fi + + local counter=0 + + while ! $command &> /dev/null; do + + if (( counter > 300 )); then + (>&2 echo "timeout while waiting on ${DB_PLATFORM} to become available") + exit 1 + fi + + sleep 2 + ((++counter)) + done +} diff --git a/docker/image/console/root/lib/task/database/import.sh.twig b/docker/image/console/root/lib/task/database/import.sh.twig new file mode 100644 index 00000000..d0742b9a --- /dev/null +++ b/docker/image/console/root/lib/task/database/import.sh.twig @@ -0,0 +1,10 @@ +#!/bin/bash + +function task_database_import() +{ + + {% for step in @('database.import.steps') -%} + {{ step|raw }} + {% endfor %} + +} diff --git a/docker/image/console/root/lib/task/http/wait.sh b/docker/image/console/root/lib/task/http/wait.sh new file mode 100644 index 00000000..5b6c05a9 --- /dev/null +++ b/docker/image/console/root/lib/task/http/wait.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +# wait for http service +function task_http_wait() { + echo -e "Waiting for http service $1 to be available" + + local counter=0 + + while ! curl -s -k "$1" -o /dev/null -L --fail; do + + if (( counter > 60 )); then + (>&2 echo "timeout while waiting on $1 to become available") + exit 1 + fi + + sleep 1 + ((++counter)) + done +} \ No newline at end of file diff --git a/docker/image/console/root/lib/task/init.sh.twig b/docker/image/console/root/lib/task/init.sh.twig new file mode 100644 index 00000000..58e04a56 --- /dev/null +++ b/docker/image/console/root/lib/task/init.sh.twig @@ -0,0 +1,18 @@ +#!/bin/bash + +function task_init() +{ + task database:available + + if ! db_hasSchema; then + + task assets:apply + + {% for step in @('backend.init.steps') -%} + {{ step|raw }} + {% endfor %} + + task welcome + + fi +} diff --git a/docker/image/console/root/lib/task/install.sh.twig b/docker/image/console/root/lib/task/install.sh.twig new file mode 100644 index 00000000..07717612 --- /dev/null +++ b/docker/image/console/root/lib/task/install.sh.twig @@ -0,0 +1,11 @@ +#!/bin/bash + +function task_install() +{ + task database:available + + {% for step in @('backend.install.steps') -%} + {{ step|raw }} + {% endfor %} + +} diff --git a/docker/image/console/root/lib/task/migrate.sh.twig b/docker/image/console/root/lib/task/migrate.sh.twig new file mode 100644 index 00000000..863a1ad4 --- /dev/null +++ b/docker/image/console/root/lib/task/migrate.sh.twig @@ -0,0 +1,10 @@ +#!/bin/bash + +function task_migrate() +{ + task database:available + + {% for step in @('backend.migrate.steps') -%} + {{ step|raw }} + {% endfor %} +} diff --git a/docker/image/console/root/lib/task/overlay/apply.sh b/docker/image/console/root/lib/task/overlay/apply.sh new file mode 100644 index 00000000..33fec2d1 --- /dev/null +++ b/docker/image/console/root/lib/task/overlay/apply.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +function task_overlay_apply() +{ + run rsync --exclude='*.twig' --exclude='_twig' -a /home/build/application/overlay/ /app/ +} diff --git a/docker/image/console/root/lib/task/phpstan.sh b/docker/image/console/root/lib/task/phpstan.sh new file mode 100644 index 00000000..bf7159f5 --- /dev/null +++ b/docker/image/console/root/lib/task/phpstan.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +function task_phpstan() +{ + local phpstan_version="" + phpstan_version="$(find_phpstan_version)" + + echo "Using phpstan v$phpstan_version" + composer global require "phpstan/phpstan:$phpstan_version" + composer global exec -v -- phpstan analyse -c /app/phpstan.neon +} + +function find_phpstan_version() +( + local phpstan_version="0.12.37" + local project_phpstan_version="" + set +e + if [ -f /app/composer.lock ]; then + project_phpstan_version="$(jq -r '."packages" + ."packages-dev" | map(select( .name == "phpstan/phpstan" )) | .[].version' /app/composer.lock)" + if [ -n "$project_phpstan_version" ]; then + phpstan_version="$project_phpstan_version" + fi + fi + echo "$phpstan_version" +) diff --git a/docker/image/console/root/lib/task/rabbitmq/vhosts.sh.twig b/docker/image/console/root/lib/task/rabbitmq/vhosts.sh.twig new file mode 100644 index 00000000..cd40eaf3 --- /dev/null +++ b/docker/image/console/root/lib/task/rabbitmq/vhosts.sh.twig @@ -0,0 +1,15 @@ +#!/bin/bash + +# create rabbitmq virtual hosts +function task_rabbitmq_vhosts() { +{% if @('services.rabbitmq.enabled') %} + local rabbitmq_api_url="http://$RABBITMQ_HOST:$RABBITMQ_API_PORT/api" + task http:wait "$rabbitmq_api_url/index.html" + +{% for vhost in @('rabbitmq.vhosts') %} + curl -f -I -s -u "$RABBITMQ_USER:$RABBITMQ_PASSWORD" -X PUT "$rabbitmq_api_url/vhosts/{{ vhost }}" +{% endfor %} +{% else %} + : +{% endif %} +} diff --git a/docker/image/console/root/lib/task/skeleton/apply.sh b/docker/image/console/root/lib/task/skeleton/apply.sh new file mode 100644 index 00000000..700ab064 --- /dev/null +++ b/docker/image/console/root/lib/task/skeleton/apply.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +function task_skeleton_apply() +{ + run rsync --exclude='*.twig' --exclude='_twig' -a /home/build/application/skeleton/ /app/ +} diff --git a/docker/image/console/root/lib/task/state.sh b/docker/image/console/root/lib/task/state.sh new file mode 100644 index 00000000..c0e00419 --- /dev/null +++ b/docker/image/console/root/lib/task/state.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +function task_state() +{ + task database:available + + echo "Ready!" +} diff --git a/docker/image/console/root/usr/local/bin/send_mail b/docker/image/console/root/usr/local/bin/send_mail new file mode 100755 index 00000000..8713095f --- /dev/null +++ b/docker/image/console/root/usr/local/bin/send_mail @@ -0,0 +1,5 @@ +#!/bin/sh + +set -e + +/usr/local/bin/mhsendmail --smtp-addr="$SMTP_HOST:$SMTP_PORT" "$@" diff --git a/docker/image/console/root/usr/local/etc/php/conf.d/docker-php-ext-blackfire.ini.twig b/docker/image/console/root/usr/local/etc/php/conf.d/docker-php-ext-blackfire.ini.twig new file mode 100644 index 00000000..10b40390 --- /dev/null +++ b/docker/image/console/root/usr/local/etc/php/conf.d/docker-php-ext-blackfire.ini.twig @@ -0,0 +1,8 @@ +{% set blackfire = @('php.ext-blackfire') %} + +{% if blackfire.cli.enable == 'yes' %} + extension=blackfire.so + {% for key, value in blackfire.config -%} + blackfire.{{ key }}={{ value }} + {% endfor %} +{% endif %} diff --git a/docker/image/console/root/usr/local/etc/php/conf.d/docker-php-ext-tideways.ini.twig b/docker/image/console/root/usr/local/etc/php/conf.d/docker-php-ext-tideways.ini.twig new file mode 100644 index 00000000..fb768799 --- /dev/null +++ b/docker/image/console/root/usr/local/etc/php/conf.d/docker-php-ext-tideways.ini.twig @@ -0,0 +1,8 @@ +{% set tideways = @('php.ext-tideways') %} + +{% if tideways.cli.enable == 'yes' %} + extension=tideways.so + {% for key, value in tideways.config -%} + tideways.{{ key }}={{ value }} + {% endfor %} +{% endif %} diff --git a/docker/image/console/root/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini.twig b/docker/image/console/root/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini.twig new file mode 100644 index 00000000..858a33ad --- /dev/null +++ b/docker/image/console/root/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini.twig @@ -0,0 +1,8 @@ +{% set xdebug = @('php.ext-xdebug') %} + +{% if xdebug.cli.enable == 'yes' %} + zend_extension=xdebug.so + {% for key, value in xdebug.config -%} + xdebug.{{ key }}={{ value }} + {% endfor %} +{% endif %} diff --git a/docker/image/console/root/usr/local/etc/php/php.ini.twig b/docker/image/console/root/usr/local/etc/php/php.ini.twig new file mode 100644 index 00000000..b76369c9 --- /dev/null +++ b/docker/image/console/root/usr/local/etc/php/php.ini.twig @@ -0,0 +1,10 @@ +{% for name, value in @('php.ini') %} +{{ name }} = {{ value }} +{% endfor %} +{% for name, value in @('php.cli.ini') %} +{{ name }} = {{ value }} +{% endfor %} + +; UTC for consistent logging that doesn't vary for Daylight Savings +; If you need to change it, configure your application to display dates offset from UTC. +date.timezone = UTC diff --git a/docker/image/cron/Dockerfile.twig b/docker/image/cron/Dockerfile.twig new file mode 100644 index 00000000..23e44743 --- /dev/null +++ b/docker/image/cron/Dockerfile.twig @@ -0,0 +1,37 @@ +{% if @('app.build') == 'static' %} +FROM {{ @('docker.repository') ~ ':' ~ @('app.version') }}-php-fpm +{% else %} +FROM {{ @('workspace.name') ~ '-php-fpm:dev' }} +{% endif %} +# fix upstream signal +STOPSIGNAL SIGTERM + +# Install cron +RUN apt-get update -qq \ + && DEBIAN_FRONTEND=noninteractive apt-get -qq -y --no-install-recommends install \ + cron \ + sudo \ + # clean \ + && apt-get auto-remove -qq -y \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /app +COPY .my127ws/docker/image/cron/root / +RUN chmod +x /cron-run-with-env.sh + +{% if @('app.build') == 'static' %} +RUN bash /fix_app_permissions.sh +{% else %} +VOLUME /app +{% endif %} +ENV APP_MODE {{ @('app.mode') }} + +{% if @('app.build') == 'static' %} +RUN chmod +x /entrypoint.sh +ENTRYPOINT ["/entrypoint.sh"] +CMD ["sleep", "infinity"] +{% else %} +ENTRYPOINT ["/entrypoint.dynamic.sh"] +CMD ["sleep", "infinity"] +{% endif %} diff --git a/docker/image/cron/root/cron-run-with-env.sh b/docker/image/cron/root/cron-run-with-env.sh new file mode 100755 index 00000000..caa047d4 --- /dev/null +++ b/docker/image/cron/root/cron-run-with-env.sh @@ -0,0 +1,5 @@ +#!/bin/bash +script_args="$*" +env_vars=() +readarray -t env_vars < /app/env.sh +/usr/bin/env - "${env_vars[@]}" su -s /bin/bash -p -c "$script_args" www-data > /proc/1/fd/1 2> /proc/1/fd/2 diff --git a/docker/image/cron/root/crontab.twig b/docker/image/cron/root/crontab.twig new file mode 100644 index 00000000..71a84dc3 --- /dev/null +++ b/docker/image/cron/root/crontab.twig @@ -0,0 +1,3 @@ +{% for cronjob in @('backend.cron.jobs') -%} +{{ cronjob|raw }} +{% endfor %} \ No newline at end of file diff --git a/docker/image/cron/root/entrypoint.sh.twig b/docker/image/cron/root/entrypoint.sh.twig new file mode 100644 index 00000000..ee0e78a4 --- /dev/null +++ b/docker/image/cron/root/entrypoint.sh.twig @@ -0,0 +1,56 @@ +#!/bin/bash + +setup_app_networking() +{ + # make linux consistent with docker-for-mac + if [ "${HOST_OS_FAMILY}" = "linux" ]; then + DOCKER_INTERNAL_HOST="host.docker.internal" + if ! grep $DOCKER_INTERNAL_HOST /etc/hosts > /dev/null ; then + DOCKER_INTERNAL_IP=$(/sbin/ip route|awk '/default/ { print $3 }') + echo -e "$DOCKER_INTERNAL_IP $DOCKER_INTERNAL_HOST" | tee -a /etc/hosts > /dev/null + fi + fi +} + +run_steps() +{ + # run any command required to be executed at docker startup + {% for step in @('php.entrypoint.steps') -%} + {{ step|raw }} + {% else -%} + : + {% endfor %} + {% for step in @('cron.entrypoint.steps') -%} + {{ step|raw }} + {% else -%} + : + {% endfor %} + + # Clean up Tideways module loading if it's meant to be turned off + if [ -n "$TIDEWAYS_ENABLED" ] && [ -f /usr/local/etc/php/conf.d/docker-php-ext-tideways.ini ]; then + if [ "$TIDEWAYS_ENABLED" = "true" ]; then + sed -i'' "s#tideways.connection=.*$#tideways.connection=tcp://$TIDEWAYS_HOST:9135#" /usr/local/etc/php/conf.d/docker-php-ext-tideways.ini + else + rm /usr/local/etc/php/conf.d/docker-php-ext-tideways.ini + fi + fi +} + +dump_environment_variables() +{ + # this is used to load env vars in crontab commands + env > /app/env.sh +} + +bootstrap() +{ + setup_app_networking + run_steps + dump_environment_variables +} + +bootstrap + +# run +crontab /crontab +exec /sbin/tini -- cron -f -L 15 diff --git a/docker/image/nginx/Dockerfile.twig b/docker/image/nginx/Dockerfile.twig new file mode 100644 index 00000000..f1076f38 --- /dev/null +++ b/docker/image/nginx/Dockerfile.twig @@ -0,0 +1,17 @@ +{% if @('app.build') == 'static' %} +FROM {{ @('docker.repository') ~ ':' ~ @('app.version') }}-console as console +{% endif %} + +FROM nginx:1.19-alpine +COPY root / + +{% if @('app.build') == 'static' %} +{% for copy_directory in @('nginx.copy_directories')|filter(v => v is not empty) %} +COPY --from=console {{ copy_directory }} {{ copy_directory }} +{% endfor %} +{% else %} +VOLUME /app +{% endif %} + +ENTRYPOINT ["sh", "/docker-entrypoint.d/config_render.sh"] +CMD ["nginx", "-g", "daemon off;"] diff --git a/docker/image/nginx/root/etc/nginx/conf.d/0-nginx.conf.twig b/docker/image/nginx/root/etc/nginx/conf.d/0-nginx.conf.twig new file mode 100644 index 00000000..c9efff8a --- /dev/null +++ b/docker/image/nginx/root/etc/nginx/conf.d/0-nginx.conf.twig @@ -0,0 +1,3 @@ +{% for name, value in @('nginx.global.conf') %} + {{ name }} {{ value }}; +{% endfor %} diff --git a/docker/image/nginx/root/etc/nginx/conf.d/default.conf.template.twig b/docker/image/nginx/root/etc/nginx/conf.d/default.conf.template.twig new file mode 100644 index 00000000..66242fd5 --- /dev/null +++ b/docker/image/nginx/root/etc/nginx/conf.d/default.conf.template.twig @@ -0,0 +1,68 @@ + +server { + + listen 80 default_server; + listen 443 ssl http2 default_server; + + server_name _; + + include snippets/certificate.conf; + include snippets/ssl-params.conf; + include snippets/top-*.conf; + + {% for name, value in @('nginx.site.conf') %} + {{ name }} {{ value }}; + {% endfor %} + + set $custom_https $https; + set $custom_scheme $scheme; + + if ($http_x_forwarded_proto) { + set $custom_scheme $http_x_forwarded_proto; + } + + if ($http_x_forwarded_proto = https) { + set $custom_https on; + } + + root {{ @('app.web_directory') }}; + + index index.php; + + location / { + try_files $uri @rewriteapp; + } + + location @rewriteapp { + rewrite ^(.*)$ /index.php/$1 last; + } + + location ~ \.php(/|$) { + + fastcgi_pass ${FPM_HOST}:9000; + fastcgi_split_path_info ^(.+\.php)(/.*)$; + include fastcgi_params; + + fastcgi_read_timeout {{ @('php.fpm.ini.max_execution_time') + 1 }}s; + + fastcgi_param HTTPS $custom_https; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + + fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info; + fastcgi_param PATH_INFO $fastcgi_path_info; + fastcgi_param HTTP_PROXY ""; + + {% for name, value in @('nginx.php_fpm.conf') %} + {{- name }} {{ value }}; + {% endfor %} + + } + + include snippets/bottom-*.conf; + + # Banned locations (only reached if the earlier PHP entry point regexes don't match) + location ~* (\.php$|\.htaccess$|\.git) { + deny all; + } + +} diff --git a/docker/image/nginx/root/etc/nginx/snippets/certificate.conf b/docker/image/nginx/root/etc/nginx/snippets/certificate.conf new file mode 100644 index 00000000..80e7be3f --- /dev/null +++ b/docker/image/nginx/root/etc/nginx/snippets/certificate.conf @@ -0,0 +1,2 @@ +ssl_certificate /etc/ssl/certs/app.crt; +ssl_certificate_key /etc/ssl/private/app.key; diff --git a/docker/image/nginx/root/etc/nginx/snippets/ssl-params.conf b/docker/image/nginx/root/etc/nginx/snippets/ssl-params.conf new file mode 100644 index 00000000..9b37b604 --- /dev/null +++ b/docker/image/nginx/root/etc/nginx/snippets/ssl-params.conf @@ -0,0 +1,17 @@ +# from https://cipherli.st/ +# and https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html + +ssl_protocols TLSv1.1 TLSv1.2; +ssl_prefer_server_ciphers on; +ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH"; +ssl_ecdh_curve secp384r1; +ssl_session_cache shared:SSL:10m; +ssl_session_tickets off; +ssl_stapling on; +ssl_stapling_verify on; + +resolver 1.1.1.1 8.8.8.8 valid=300s; +resolver_timeout 5s; + +add_header Strict-Transport-Security "max-age=63072000; includeSubdomains"; +add_header X-Content-Type-Options nosniff; diff --git a/docker/image/nginx/root/etc/ssl/certs/app.crt.twig b/docker/image/nginx/root/etc/ssl/certs/app.crt.twig new file mode 100644 index 00000000..0d945815 --- /dev/null +++ b/docker/image/nginx/root/etc/ssl/certs/app.crt.twig @@ -0,0 +1 @@ +{{ @('tls.crt') }} \ No newline at end of file diff --git a/docker/image/nginx/root/etc/ssl/private/app.key.twig b/docker/image/nginx/root/etc/ssl/private/app.key.twig new file mode 100644 index 00000000..6bb8bcbf --- /dev/null +++ b/docker/image/nginx/root/etc/ssl/private/app.key.twig @@ -0,0 +1 @@ +{{ @('tls.key') }} \ No newline at end of file diff --git a/docker/image/php-fpm/.dockerignore b/docker/image/php-fpm/.dockerignore new file mode 100644 index 00000000..cf49d54d --- /dev/null +++ b/docker/image/php-fpm/.dockerignore @@ -0,0 +1 @@ +**/*.twig diff --git a/docker/image/php-fpm/Dockerfile.twig b/docker/image/php-fpm/Dockerfile.twig new file mode 100644 index 00000000..1234df0b --- /dev/null +++ b/docker/image/php-fpm/Dockerfile.twig @@ -0,0 +1,37 @@ +{% if @('app.build') == 'static' %} +FROM {{ @('docker.repository') ~ ':' ~ @('app.version') }}-console as console +RUN if [ -d /app/tools/assets/ ]; then rm -rf /app/tools/assets/; fi +RUN if [ -d {{ @('frontend.path') }}/node_modules/ ]; then rm -rf {{ @('frontend.path') }}/node_modules/; fi +{% endif %} + +FROM {{ @('docker.image.php-fpm') }} +WORKDIR /app +COPY root / + +RUN curl --fail --silent --location --output /sbin/tini https://github.com/krallin/tini/releases/download/v0.19.0/tini \ + && chmod +x /sbin/tini \ + && curl --fail --silent --location --output /usr/local/bin/mhsendmail https://github.com/mailhog/mhsendmail/releases/download/v0.2.0/mhsendmail_linux_amd64 \ + && chmod +x /usr/local/bin/mhsendmail +{%- set install_extensions=@('php.install_extensions')|merge(@('php.fpm.install_extensions'))|filter(v => v is not empty) %} +{%- if install_extensions %} \ + && cd /root/installer \ + && ./enable.sh \ + {{ install_extensions|join(" \\\n ") }} +{% endif %} + +{% if @('app.build') == 'static' %} +COPY --from=console --chown=root:root /app /app +RUN bash /fix_app_permissions.sh +{% else %} +VOLUME /app +{% endif %} +ENV APP_MODE {{ @('app.mode') }} + +{% if @('app.build') == 'static' %} +RUN chmod +x /entrypoint.sh +ENTRYPOINT ["/entrypoint.sh"] +CMD ["sleep", "infinity"] +{% else %} +ENTRYPOINT ["/entrypoint.dynamic.sh"] +CMD ["sleep", "infinity"] +{% endif %} diff --git a/docker/image/php-fpm/root/app/.gitkeep b/docker/image/php-fpm/root/app/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/docker/image/php-fpm/root/entrypoint.dynamic.sh b/docker/image/php-fpm/root/entrypoint.dynamic.sh new file mode 100755 index 00000000..b9bf82f2 --- /dev/null +++ b/docker/image/php-fpm/root/entrypoint.dynamic.sh @@ -0,0 +1,69 @@ +#!/bin/bash + +main() +{ + source /entrypoint.sh +} + +setup_app_networking() +{ + # make linux consistent with docker-for-mac + if [ "${HOST_OS_FAMILY}" = "linux" ]; then + DOCKER_INTERNAL_HOST="host.docker.internal" + if ! grep $DOCKER_INTERNAL_HOST /etc/hosts > /dev/null ; then + DOCKER_INTERNAL_IP=$(/sbin/ip route|awk '/default/ { print $3 }') + echo -e "$DOCKER_INTERNAL_IP $DOCKER_INTERNAL_HOST" | tee -a /etc/hosts > /dev/null + fi + fi +} + +setup_app_volume_permissions() +{ + case "$STRATEGY" in + "host-linux-normal") + usermod -u "$(stat -c '%u' /app)" www-data + groupmod -g "$(stat -c '%g' /app)" www-data + ;; + "host-osx-normal") + usermod -u 1000 www-data + groupmod -g 1000 www-data + ;; + "host-osx-dockersync") + usermod -u 1000 www-data + groupmod -g 1000 www-data + ;; + *) + exit 1 + esac +} + +resolve_volume_mount_strategy() +{ + if [ "${HOST_OS_FAMILY}" = "linux" ]; then + STRATEGY="host-linux-normal" + elif [ "${HOST_OS_FAMILY}" = "darwin" ]; then + if (mount | grep "/app type fuse.osxfs") > /dev/null 2>&1; then + STRATEGY="host-osx-normal" + elif (mount | grep "/app type fuse.grpcfuse") > /dev/null 2>&1; then + STRATEGY="host-osx-normal" + elif (mount | grep "/app type ext4") > /dev/null 2>&1; then + STRATEGY="host-osx-dockersync" + elif (mount | grep "/app type btrfs") > /dev/null 2>&1; then + STRATEGY="host-linux-normal" + else + exit 1 + fi + else + exit 1 + fi +} + +bootstrap() +{ + resolve_volume_mount_strategy + setup_app_volume_permissions + setup_app_networking +} + +bootstrap +main diff --git a/docker/image/php-fpm/root/entrypoint.sh.twig b/docker/image/php-fpm/root/entrypoint.sh.twig new file mode 100755 index 00000000..56237cb4 --- /dev/null +++ b/docker/image/php-fpm/root/entrypoint.sh.twig @@ -0,0 +1,30 @@ +#!/bin/bash + +run_steps() +{ + {% for poolName, pool in @('php-fpm.pools') -%} + FPM_NAME="{{ poolName }}" FPM_PORT="{{ pool.port }}" envsubst < /usr/local/etc/php-fpm.d/pool.conf.template > /usr/local/etc/php-fpm.d/{{ poolName }}.conf; + {% endfor %} + + # run any command required to be executed at docker startup + {% for step in @('php.entrypoint.steps') -%} + {{ step|raw }} + {% endfor %} + {% for step in @('php-fpm.entrypoint.steps') -%} + {{ step|raw }} + {% endfor %} + + # Clean up Tideways module loading if it's meant to be turned off + if [ -n "$TIDEWAYS_ENABLED" ] && [ -f /usr/local/etc/php/conf.d/docker-php-ext-tideways.ini ]; then + if [ "$TIDEWAYS_ENABLED" = "true" ]; then + sed -i'' "s#tideways.connection=.*$#tideways.connection=tcp://$TIDEWAYS_HOST:9135#" /usr/local/etc/php/conf.d/docker-php-ext-tideways.ini + else + rm /usr/local/etc/php/conf.d/docker-php-ext-tideways.ini + fi + fi +} + +run_steps + +# run +exec supervisord -c /etc/supervisor/supervisord.conf -n diff --git a/docker/image/php-fpm/root/etc/supervisor/conf.d/container-cmd.conf b/docker/image/php-fpm/root/etc/supervisor/conf.d/container-cmd.conf new file mode 100644 index 00000000..a96f50ea --- /dev/null +++ b/docker/image/php-fpm/root/etc/supervisor/conf.d/container-cmd.conf @@ -0,0 +1,9 @@ +[program:php-fpm] +command=docker-php-entrypoint php-fpm +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +user = root +autostart = %(ENV_AUTOSTART_PHP_FPM)s +autorestart = true diff --git a/docker/image/php-fpm/root/etc/supervisor/supervisord.conf b/docker/image/php-fpm/root/etc/supervisor/supervisord.conf new file mode 100644 index 00000000..6cfe17a9 --- /dev/null +++ b/docker/image/php-fpm/root/etc/supervisor/supervisord.conf @@ -0,0 +1,18 @@ +[supervisord] +nodaemon = true +logfile=/dev/stdout +logfile_maxbytes=0 +pidfile = /var/run/supervisord.pid + +[include] +files = /etc/supervisor/conf.d/*.conf + +[supervisorctl] +serverurl = unix:///var/run/supervisor.sock + +[unix_http_server] +file = /var/run/supervisor.sock +chmod = 0700 + +[rpcinterface:supervisor] +supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface diff --git a/docker/image/php-fpm/root/fix_app_permissions.sh.twig b/docker/image/php-fpm/root/fix_app_permissions.sh.twig new file mode 100755 index 00000000..705b8ab9 --- /dev/null +++ b/docker/image/php-fpm/root/fix_app_permissions.sh.twig @@ -0,0 +1,55 @@ +#!/bin/bash + +set -o errexit +set -o pipefail +set -o nounset + + +main() +{ + app_permissions_fix +} + + +function app_permissions_fix() +{ + local APP_OWNER="{{ @('app.web_owner') }}" + local APP_GROUP="{{ @('app.web_group') }}" + DIRS=("{{ @('app.web_writable_dirs') | join('" "') | raw }}") + FILES=("{{ @('app.web_writable_files') | join('" "') | raw }}") + + for DIR in "${DIRS[@]}" + do + if [ -n "${DIR}" ]; then + if [ ! -d "${DIR}" ]; then + echo "${DIR} does not exist. Creating ${DIR}..." + mkdir -p "${DIR}" + fi + echo -n "Fixing permissions for ${DIR}..." + find "${DIR}" \( ! -user "${APP_OWNER}" -or ! -group "${APP_GROUP}" \) -exec chown "${APP_OWNER}":"${APP_GROUP}" {} + + find "${DIR}" -type d ! -perm ug+rwx,o+rx,o-w -exec chmod ug+rwx,o+rx,o-w {} + + find "${DIR}" -type f ! -perm ug+rw,o+r,o-w -exec chmod ug+rw,o+r,o-w {} + + echo "Done" + else + echo "No directory was specified for permissions fixing." + fi + done + + for FILE in "${FILES[@]}" + do + if [ -n "${FILE}" ]; then + if [ ! -f "${FILE}" ]; then + echo "${FILE} does not exist. Creating ${FILE}..." + touch "${FILE}" + fi + echo -n "Fixing permissions for ${FILE}..." + chown "${APP_OWNER}":"${APP_GROUP}" "${FILE}" + chmod ug+rw,o+r,o-w "${FILE}" + echo "Done" + else + echo "No file was specified for permissions fixing." + fi + done +} + +main diff --git a/docker/image/php-fpm/root/usr/local/bin/send_mail b/docker/image/php-fpm/root/usr/local/bin/send_mail new file mode 100755 index 00000000..8713095f --- /dev/null +++ b/docker/image/php-fpm/root/usr/local/bin/send_mail @@ -0,0 +1,5 @@ +#!/bin/sh + +set -e + +/usr/local/bin/mhsendmail --smtp-addr="$SMTP_HOST:$SMTP_PORT" "$@" diff --git a/docker/image/php-fpm/root/usr/local/etc/php-fpm.d/pool.conf.template.twig b/docker/image/php-fpm/root/usr/local/etc/php-fpm.d/pool.conf.template.twig new file mode 100644 index 00000000..14a055d8 --- /dev/null +++ b/docker/image/php-fpm/root/usr/local/etc/php-fpm.d/pool.conf.template.twig @@ -0,0 +1,24 @@ +[${FPM_NAME}] +user = www-data +group = www-data + +listen = ${FPM_PORT} + +pm = dynamic + +pm.max_children = 5 +pm.start_servers = 2 +pm.min_spare_servers = 1 +pm.max_spare_servers = 3 + +pm.status_path = /status + +; if we send this to /proc/self/fd/1, it never appears +access.log = /proc/self/fd/2 + +clear_env = no + +catch_workers_output = yes +{% if version_compare(@('php.version'), '7.3.0', '>=') %} +decorate_workers_output = no +{% endif %} diff --git a/docker/image/php-fpm/root/usr/local/etc/php/conf.d/docker-php-ext-blackfire.ini.twig b/docker/image/php-fpm/root/usr/local/etc/php/conf.d/docker-php-ext-blackfire.ini.twig new file mode 100644 index 00000000..36004a92 --- /dev/null +++ b/docker/image/php-fpm/root/usr/local/etc/php/conf.d/docker-php-ext-blackfire.ini.twig @@ -0,0 +1,8 @@ +{% set blackfire = @('php.ext-blackfire') %} + +{% if blackfire.enable == 'yes' %} + extension=blackfire.so + {% for key, value in blackfire.config -%} + blackfire.{{ key }}={{ value }} + {% endfor %} +{% endif %} diff --git a/docker/image/php-fpm/root/usr/local/etc/php/conf.d/docker-php-ext-tideways.ini.twig b/docker/image/php-fpm/root/usr/local/etc/php/conf.d/docker-php-ext-tideways.ini.twig new file mode 100644 index 00000000..1abf29eb --- /dev/null +++ b/docker/image/php-fpm/root/usr/local/etc/php/conf.d/docker-php-ext-tideways.ini.twig @@ -0,0 +1,8 @@ +{% set tideways = @('php.ext-tideways') %} + +{% if tideways.enable == 'yes' %} + extension=tideways.so + {% for key, value in tideways.config -%} + tideways.{{ key }}={{ value }} + {% endfor %} +{% endif %} diff --git a/docker/image/php-fpm/root/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini.twig b/docker/image/php-fpm/root/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini.twig new file mode 100644 index 00000000..1c319dad --- /dev/null +++ b/docker/image/php-fpm/root/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini.twig @@ -0,0 +1,8 @@ +{% set xdebug = @('php.ext-xdebug') %} + +{% if xdebug.enable == 'yes' %} + zend_extension=xdebug.so + {% for key, value in xdebug.config -%} + xdebug.{{ key }}={{ value }} + {% endfor %} +{% endif %} diff --git a/docker/image/php-fpm/root/usr/local/etc/php/php.ini.twig b/docker/image/php-fpm/root/usr/local/etc/php/php.ini.twig new file mode 100644 index 00000000..90f4ad60 --- /dev/null +++ b/docker/image/php-fpm/root/usr/local/etc/php/php.ini.twig @@ -0,0 +1,10 @@ +{% for name, value in @('php.ini') %} +{{ name }} = {{ value }} +{% endfor %} +{% for name, value in @('php.fpm.ini') %} +{{ name }} = {{ value }} +{% endfor %} + +; UTC for consistent logging that doesn't vary for Daylight Savings +; If you need to change it, configure your application to display dates offset from UTC. +date.timezone = UTC diff --git a/docker/image/relay/Dockerfile b/docker/image/relay/Dockerfile new file mode 100644 index 00000000..8a2f629f --- /dev/null +++ b/docker/image/relay/Dockerfile @@ -0,0 +1,2 @@ +FROM nginx:1.19-alpine +COPY root / diff --git a/docker/image/relay/root/etc/nginx/nginx.conf b/docker/image/relay/root/etc/nginx/nginx.conf new file mode 100644 index 00000000..8f51cf3c --- /dev/null +++ b/docker/image/relay/root/etc/nginx/nginx.conf @@ -0,0 +1,24 @@ +user nginx; +worker_processes auto; + +error_log /var/log/nginx/error.log warn; +pid /var/run/nginx.pid; + + +events { + worker_connections 1024; +} + +stream { + server { + listen 1025; + + proxy_pass mailhog:1025; + } + + server { + listen 8025; + + proxy_pass mailhog:8025; + } +} diff --git a/docker/image/solr4/Dockerfile b/docker/image/solr4/Dockerfile new file mode 100644 index 00000000..1fde4fdf --- /dev/null +++ b/docker/image/solr4/Dockerfile @@ -0,0 +1,37 @@ +FROM solr:5-slim + +ARG SOLR_VERSION="4.10.4" +ARG SOLR_SHA512="f7a83504e0f9a4c81b0acafdf452c0c05fcbdf185375f383450bef4fd478812b5259705b55203460d03da46add12cec2442d399ad3716e4e11c393a9a9a01b03" + +USER root + +# Install SOLR 4 over the top of SOLR 5 from instructions in +# https://github.com/docker-solr/docker-solr/blob/master/5.5/slim/Dockerfile +RUN rm -rf /opt/solr \ + && wget -t 10 --max-redirect 1 --retry-connrefused -nv "https://archive.apache.org/dist/lucene/solr/$SOLR_VERSION/solr-$SOLR_VERSION.tgz" -O "/opt/solr-$SOLR_VERSION.tgz" \ + && echo "$SOLR_SHA512 */opt/solr-$SOLR_VERSION.tgz" | sha512sum -c - \ + && tar -C /opt --extract --file "/opt/solr-$SOLR_VERSION.tgz" \ + && mv "/opt/solr-$SOLR_VERSION" /opt/solr \ + && rm "/opt/solr-$SOLR_VERSION.tgz"* \ + && rm -Rf /opt/solr/docs/ /opt/solr/dist/{solr-core-$SOLR_VERSION.jar,solr-solrj-$SOLR_VERSION.jar,solrj-lib,solr-test-framework-$SOLR_VERSION.jar,test-framework} /opt/solr/example/solr/collection1 \ + && mkdir -p /opt/solr/server/solr/lib /opt/solr/server/solr/mycores /opt/solr/server/logs \ + && sed -i -e "s/\"\$(whoami)\" == \"root\"/\$(id -u) == 0/" /opt/solr/bin/solr \ + && sed -i -e 's/lsof -PniTCP:/lsof -t -PniTCP:/' /opt/solr/bin/solr \ + && sed -i 's#! -d \$coredir #! -d "$coredir/conf/" #' /opt/docker-solr/scripts/precreate-core \ + && if [ -f "/opt/solr/contrib/prometheus-exporter/bin/solr-exporter" ]; then chmod 0755 "/opt/solr/contrib/prometheus-exporter/bin/solr-exporter"; fi \ + && chown -R "$SOLR_USER:$SOLR_GROUP" /opt/solr /docker-entrypoint-initdb.d /opt/docker-solr \ + && chown -R "$SOLR_USER:$SOLR_GROUP" /opt/mysolrhome /opt/solr/example/solr \ + \ + # Install unzip to allow solr to start \ + && apt-get -qq update \ + && apt-get -qq -y --no-install-recommends install \ + unzip \ + \ + # Clean the image \ + && apt-get autoremove -qq \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +ENV SOLR_HOME=/opt/solr/example/solr + +USER $SOLR_USER diff --git a/docker/image/tls-offload/Dockerfile b/docker/image/tls-offload/Dockerfile new file mode 100644 index 00000000..8a2f629f --- /dev/null +++ b/docker/image/tls-offload/Dockerfile @@ -0,0 +1,2 @@ +FROM nginx:1.19-alpine +COPY root / diff --git a/docker/image/tls-offload/root/etc/nginx/conf.d/0-nginx.conf.twig b/docker/image/tls-offload/root/etc/nginx/conf.d/0-nginx.conf.twig new file mode 100644 index 00000000..c9efff8a --- /dev/null +++ b/docker/image/tls-offload/root/etc/nginx/conf.d/0-nginx.conf.twig @@ -0,0 +1,3 @@ +{% for name, value in @('nginx.global.conf') %} + {{ name }} {{ value }}; +{% endfor %} diff --git a/docker/image/tls-offload/root/etc/nginx/conf.d/default.conf.twig b/docker/image/tls-offload/root/etc/nginx/conf.d/default.conf.twig new file mode 100644 index 00000000..d7ee4666 --- /dev/null +++ b/docker/image/tls-offload/root/etc/nginx/conf.d/default.conf.twig @@ -0,0 +1,47 @@ + +server { + + listen 80 default_server; + listen 443 ssl http2 default_server; + + server_name _; + + include snippets/certificate.conf; + include snippets/ssl-params.conf; + include snippets/top-*.conf; + + {% for name, value in @('nginx.site.conf') %} + {{ name }} {{ value }}; + {% endfor %} + + set $custom_https $https; + set $custom_scheme $scheme; + + if ($http_x_forwarded_proto) { + set $custom_scheme $http_x_forwarded_proto; + } + + if ($http_x_forwarded_proto = https) { + set $custom_https on; + } + + root {{ @('app.web_directory') }}; + + index index.php; + + location / { + proxy_pass http://varnish; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $custom_scheme; + proxy_buffers 4 256k; + proxy_buffer_size 128k; + proxy_busy_buffers_size 256k; + proxy_read_timeout {{ @('php.fpm.ini.max_execution_time') + 3 }}s; + proxy_send_timeout {{ @('php.fpm.ini.max_execution_time') + 3 }}s; + proxy_connect_timeout {{ @('php.fpm.ini.max_execution_time') + 3 }}s; + send_timeout {{ @('php.fpm.ini.max_execution_time') + 3 }}s; + } + + include snippets/bottom-*.conf; +} diff --git a/docker/image/tls-offload/root/etc/nginx/snippets/certificate.conf b/docker/image/tls-offload/root/etc/nginx/snippets/certificate.conf new file mode 100644 index 00000000..80e7be3f --- /dev/null +++ b/docker/image/tls-offload/root/etc/nginx/snippets/certificate.conf @@ -0,0 +1,2 @@ +ssl_certificate /etc/ssl/certs/app.crt; +ssl_certificate_key /etc/ssl/private/app.key; diff --git a/docker/image/tls-offload/root/etc/nginx/snippets/ssl-params.conf b/docker/image/tls-offload/root/etc/nginx/snippets/ssl-params.conf new file mode 100644 index 00000000..9b37b604 --- /dev/null +++ b/docker/image/tls-offload/root/etc/nginx/snippets/ssl-params.conf @@ -0,0 +1,17 @@ +# from https://cipherli.st/ +# and https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html + +ssl_protocols TLSv1.1 TLSv1.2; +ssl_prefer_server_ciphers on; +ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH"; +ssl_ecdh_curve secp384r1; +ssl_session_cache shared:SSL:10m; +ssl_session_tickets off; +ssl_stapling on; +ssl_stapling_verify on; + +resolver 1.1.1.1 8.8.8.8 valid=300s; +resolver_timeout 5s; + +add_header Strict-Transport-Security "max-age=63072000; includeSubdomains"; +add_header X-Content-Type-Options nosniff; diff --git a/docker/image/tls-offload/root/etc/ssl/certs/app.crt.twig b/docker/image/tls-offload/root/etc/ssl/certs/app.crt.twig new file mode 100644 index 00000000..0d945815 --- /dev/null +++ b/docker/image/tls-offload/root/etc/ssl/certs/app.crt.twig @@ -0,0 +1 @@ +{{ @('tls.crt') }} \ No newline at end of file diff --git a/docker/image/tls-offload/root/etc/ssl/private/app.key.twig b/docker/image/tls-offload/root/etc/ssl/private/app.key.twig new file mode 100644 index 00000000..6bb8bcbf --- /dev/null +++ b/docker/image/tls-offload/root/etc/ssl/private/app.key.twig @@ -0,0 +1 @@ +{{ @('tls.key') }} \ No newline at end of file diff --git a/docker/image/varnish/root/etc/varnish/default.vcl.twig b/docker/image/varnish/root/etc/varnish/default.vcl.twig new file mode 100644 index 00000000..971517ba --- /dev/null +++ b/docker/image/varnish/root/etc/varnish/default.vcl.twig @@ -0,0 +1,41 @@ +# +# This is an example VCL file for Varnish. +# +# It does not do anything by default, delegating control to the +# builtin VCL. The builtin VCL is called when there is no explicit +# return statement. +# +# See the VCL chapters in the Users Guide for a comprehensive documentation +# at https://www.varnish-cache.org/docs/. + +# Marker to tell the VCL compiler that this VCL has been written with the +# 4.0 or 4.1 syntax. +vcl 4.1; + +# Default backend definition. Set this to point to your content server. +backend default { + .host = "{% if varnish.target_service is defined %}{{ varnish.target_service }}{% else %}{{ @('varnish.target_service') }}{% endif %}"; + .port = "80"; + .first_byte_timeout = {{ @('php.fpm.ini.max_execution_time') + 2 }}s; +} + +sub vcl_recv { + # Happens before we check if we have this in cache already. + # + # Typically you clean up the request here, removing cookies you don't need, + # rewriting the request, etc. +} + +sub vcl_backend_response { + # Happens after we have read the response headers from the backend. + # + # Here you clean the response headers, removing silly Set-Cookie headers + # and other mistakes your backend does. +} + +sub vcl_deliver { + # Happens when we have all the pieces we need, and are about to send the + # response to the client. + # + # You can do accounting or modifying the final object here. +} diff --git a/docs/.gitkeep b/docs/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/harness/attributes/common.yml b/harness/attributes/common.yml new file mode 100644 index 00000000..9fdfd68a --- /dev/null +++ b/harness/attributes/common.yml @@ -0,0 +1,433 @@ + + +attributes.default: + + app: + # build - static|dynamic + # dynamic - volumes are mounted and the build step is run once the containers have started + # static - app is copied into console, built, then the resulting build is copied into the web image + build: dynamic + + # mode - development|production + # development - additional tooling is made available and application is run in development mode + # production - leaner images with less tooling and application is run in production mode + mode: development + + services: [mysql] + web_owner: www-data + web_group: www-data + web_writable_dirs: [] + web_writable_files: [] + + web_directory: /app/public + vendor_directory: /app/vendor + + delegated-volumes: no + docker-sync: no + mutagen: yes + + jenkins: + credentials: + my127ws_key: = @('workspace.name') ~ '-my127ws-key' + + pipeline: + base: + persistence: = @('persistence') + resourcePrefix: ~ + hostname: = @('pipeline.preview.hostname') + publish: + enabled: no + services: = publishable_services(@('services')) + # branches that should publish (other than change requests and qa) + # * is deprecated and will be limited to one branch by default in a future release + branches: + - '*' + # For defining environment variables in Jenkins, e.g. loading up docker username/password from a Jenkins + # credential + environment: {} + # when enabled the application helm chart will be published + # to the given git repository. + chart: + enabled: no + git: + key: ~ # deprecated, use ssh_private_key + # private key with write access to the repository + ssh_private_key: = @('pipeline.publish.chart.git.key') + # eg. git@github.com:organisation/project.git + repository: ~ + # path within the repository to place the chart, no leading or trailing slashes + # note: an additional directory with the branch name will be created + path: = 'build-artifacts/' ~ @('workspace.name') + # sets the git user.email before pushing the commit + email: name@example.com + preview: + enabled: no + target_branches: + - = @('git.default_branch') + environment: {} + cluster: + name: null + namespace: = @('workspace.name') ~ '-' ~ slugify(branch()) + hostname: = @('pipeline.preview.namespace') ~ '.example.com' + rabbitmq: + external_host: = 'rabbitmq-' ~ @('pipeline.preview.hostname') + smtp: + host: mailhog.mailhog.svc.cluster.local + port: = @('smtp.port') + persistence: + redis_session: + enabled: false + qa: + enabled: no + environment: {} + branch: develop + cluster: + name: null + namespace: = @('workspace.name') ~ '-' ~ 'qa' + hostname: = @('pipeline.qa.namespace') ~ '.example.com' + resourcePrefix: ~ + persistence: ~ + rabbitmq: + external_host: = 'rabbitmq-' ~ @('pipeline.qa.hostname') + smtp: + host: mailhog.mailhog.svc.cluster.local + port: = @('smtp.port') + + docker: + registry: + url: = get_docker_registry(@('docker.repository')) + username: = @('docker.username') # for backwards compatibility + password: = @('docker.password') # for backwards compatibility + repository: = @("workspace.name") + compose: + file_version: '3.7' + host_volume_options: "= ':' ~ (@('delegated-volumes') ? 'delegated' : 'cached')" + config: null # deprecated + # If using gitops helm chart repositories, it's recommended to put this configuration + # in the values.yml in there now instead of project application repositories + image_pull_config: = @('docker.config') + image: + console: "= 'my127/php:' ~ @('php.version') ~ '-fpm-' ~ (@('php.version') >= 7.4 ? 'buster' : 'stretch') ~ '-console'" + php-fpm: "= 'my127/php:' ~ @('php.version') ~ '-fpm-' ~ (@('php.version') >= 7.4 ? 'buster' : 'stretch')" + port_forward: + enabled: "= @('app.build') == 'dynamic'" + composer: + auth: + basic: ~ + github: ~ + + backend: + path: /app + build: + when: -f "composer.json" + steps: + - task composer:install + install: + steps: [] + init: + steps: [] + migrate: + steps: [] + cron: + jobs: [] + + framework: + readme_blocks: [] + + frontend: + path: /app + watch: npm run watch + build: + when: -f "package.json" + steps: + - | + if [ "$APP_BUILD" == "static" ] && [ -f package-lock.json ]; then + run npm clean-install + else + run npm install + fi + - | + if [ "$(jq ".scripts.build != null" < package.json)" != "false" ]; then + run npm run build + fi + - | + if [ "$APP_BUILD" == "static" ]; then + run rm -rf node_modules/ + run npm cache clean --force + fi + + git: + default_branch: = @('git.main_branch') + # potentially deprecated, unless it is repurposed + main_branch: develop + + nginx: + # used to set site specific configurations under server directive + site: + conf: [] + # used to set nginx global configurations under http directive + global: + conf: [] + # used to limit what is copied into an Nginx static-built image + copy_directories: + - = @('app.web_directory') + php_fpm: + conf: [] + + node: + # only set this attribute if you wish to override the supplied node version, by default + # the supplied version will be the current LTS. + version: null + + php: + version: 7.4 + cli: + ini: + max_execution_time: 0 + memory_limit: -1 + install_extensions: [] + entrypoint: + steps: [] + fpm: + ini: + disable_functions: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals + expose_php: Off + log_errors: On + max_execution_time: 30 + max_input_time: 60 + memory_limit: 1024M + output_buffering: 4096 + register_argc_argv: Off + request_order: GP + variables_order: GPCS + install_extensions: [] + ini: + enable_dl: Off + error_reporting: "E_ALL" + opcache.enable_cli: On + realpath_cache_ttl: 600 + sendmail_path: /usr/local/bin/send_mail + short_open_tag: Off + install_extensions: + - "= @('services.blackfire.enabled') ? 'blackfire' : ''" + - "= @('services.tideways.enabled') ? 'tideways' : ''" + ext-blackfire: + enable: no + cli: + enable: no + config: + agent_socket: "tcp://blackfire:8707" + ext-tideways: + enable: "= @('services.tideways.enabled')" + cli: + enable: "= @('services.tideways.enabled')" + config: + connection: "tcp://tideways:9135" + collect: tracing + sample_rate: 25 + service: web + ext-xdebug: + enable: no + cli: + enable: no + config: + remote_enable: 1 + remote_autostart: 1 + remote_port: 9000 + remote_host: host.docker.internal + idekey: workspace + + assets: + remote: ="s3://"~@("aws.bucket")~"/development" + local: tools/assets/development + + cron: + entrypoint: + steps: [] + + console: + entrypoint: + steps: [] + + database: + # possible platforms are mysql, postgres or ~ for none + platform: mysql + platform_version: 5.7 + host: mysql + port: 3306 + user: app + pass: app + name: app + root_pass: DV6RdNY3QcFsBk7V + port_forward: ~ + var: + default_authentication_plugin: "= (@('database.platform') == 'mysql' && @('database.platform_version') >= 8.0 && @('database.platform_version') < 10.0 ? 'mysql_native_password' : '')" + ignore-db-dir: "= (@('database.platform') == 'mysql' && @('database.platform_version') < 8.0 ? 'lost+found' : '')" + max_allowed_packet: 4M + import: + steps: [] + + elasticsearch: + host: elasticsearch + image: elasticsearch + port: 9200 + tag: 7.1.1 + + domain: my127.site + hostname: = @('namespace') ~ '.' ~ @('domain') + hostname_aliases: [] + + helm: + additional_schema_locations: https://inviqa.github.io/kubernetes-json-schema/schema + feature: + # Note: be very careful considering disabling this, as in most cases + # it causes the secrets in it to be stored plaintext on filesystem + # or in helm chart repositories + # requires sealed-secrets k8s operator + sealed_secrets: false + timeout: 300 + + sealed_secrets: + # location of the sealed-secret service to download the active certificate from + controller_name: sealed-secrets + controller_namespace: sealed-secrets + # Use local file (or fetch from http url) as the certificate + # If null, it will be fetched from the controller in the current kubectl context + certificate_file: ~ + # A namespace the secret should be only decryptable by + # Ignored if scope is cluster-wide. + # If null, it will be fetched from the current kubectl context + namespace: ~ + # The scope under which a secret can be decrypted + # Either cluster-wide, namespace-wide, or strict + scope: "= @('helm.sealed_secrets.namespace') ? 'namespace-wide' : 'cluster-wide'" + + php-fpm: + pools: + www: + port: 9000 + entrypoint: + steps: [] + + mysql: + image: mysql + tag: 5.7 + + rabbitmq: + image: rabbitmq + tag: 3.8-management-alpine + api_port: 15672 + erlang_cookie: TeTTiwT9y548yIcfw4peaOrqgtLItD6B + external_host: = 'rabbitmq-' ~ @('hostname') + host: rabbitmq + port: 5672 + user: rabbitmq + password: rabbitmq + vhosts: + default: '/' + + redis: + host: redis + port: 6379 + + redis_session: + host: redis-session + port: 6379 + + smtp: + host: 'mailhog-relay' + port: 1025 + + varnish: + target_service: nginx + + resources: + cpu: + requests: [] + limits: [] + memory: + app_init: "1024Mi" + app_migrate: "1024Mi" + + replicas: + varnish: 1 + + persistence: + enabled: false + mountVolumesOnConsole: true # possible to disable, but may lead to unexpected concequences with app init/migrate + + elasticsearch: + enabled: true + accessMode: ReadWriteOnce + size: 2Gi + mysql: + enabled: true + accessMode: ReadWriteOnce + size: 4Gi + rabbitmq: + enabled: true + accessMode: ReadWriteOnce + size: 2Gi + postgres: + enabled: true + accessMode: ReadWriteOnce + size: 4Gi + redis: + enabled: false + accessMode: ReadWriteOnce + size: 2Gi + redis_session: + enabled: true + accessMode: ReadWriteOnce + size: 2Gi + + tls: + key: | + -----BEGIN PRIVATE KEY----- + MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC9q3EMGDtDNKAt + CHyM1MfWUaIGsv5Zka7pfjIOKL/KvrSIVpZyyJ3lSALeRyyDDRZeYwkbkNdDJgir + FmD0vJkYifYWfGdIJmbjdm62LGyzDf79Ve8aQF0lLcedMhoCfu7+qciIYnjHdvkx + Y6Fo9CTZP7m+oSNmUjHdJD3scX4l3vodBK67Hpk+W2eEhwAxG5aFsspDnPi4L9ha + KlMps+eSn1hLLGYrmthtP2assckvdyL10hS7+OOZFmj5vxGNbQn2F4whiu06JmXL + oO8T9yd8XNN383FjREYKjrQcyJo3izvawEgrRi9mNKM9DhWuBdbYNe/cSgGfwBK6 + Kc9e8zCLAgMBAAECggEAVL6fOgoxoGuJDdX24G3KBCZhQKEFKDwBbO4nq0/lsc7X + lvspKYwdkG5Gac5fQwa78dxKG3jx1VzPDrJnC7KgrOgnfhCDjScrXYJzIQ5kWvRr + 9AFLXe1YMN5ti/zwxiC05DA0G0v0LxsnaDvdyKkdNbxVX6lbycH76ZTh3h0vgfeD + Wc8MMlRTa+ORWKoIZsm+qnNLhWQhhbmoA8LNkZqtJIOBZuyAu8vyXzrEFIhKqVzU + Jdz0S+xtgYUkoXCTgdYiqoFjlKhaIIV2Fc0vbc68ziIiu3ZtaVch7wNyftoXyjBr + hjI1GT1dr7NsQpPZ6xtqjGhIvUuVSeCSBZeeXkymAQKBgQDsxFb916gIxl3QQYPV + NiKPi3rZD5iuMTjy0937dhHWGGYlWW2GEE0XjWrmLUnGyLuxwA5kFgS0eMubbhTg + aeewHamHeN/pcJIF6HndJbqXLB148E8ux6grpQrHKpTb2RLOPkd6bAgn1SjPllCL + a/vVanevaJs8U27sKEfGND0aCwKBgQDNE7IzvD1JAUrzqzG9Lxg+NhaHQTQfW45W + cuHvESiyhc93kdufvcCTrrRRXSZOqDN26+64Ni62O/ulduq4qZmhG/lxqSz5mnpr + 2oV2Kg1C1EUC4V2B9WQoMOhvOa0esTVSm9hC4oX0kYIzl6HbVAUGe8JMXOoKTJkV + 3sAz0FbTgQKBgQC1CX+2wvIiG4NaHO4v1h/hAHajiDBnaQ2xZtzCTMpgmPFpt5Ju + QwKfcqt9ar2RuKUDyeV3E/ru/7o3k5l06qWUXWnmQz96oG+XAuZDeXjN5JZ4hc8V + 5uYo0R6HoYCHBdlCSA6hhf9Kbcuxxq65nIzH54uyXNrt6qHTAw22ePULdwKBgQCK + vp+a1ukToldGQfV1zA330Pou6dNMv9Gt9S2cY5yII3W4rKrNCUDn6ZO/VGkdYDjp + ZTft02KJEk3vpWOqKbxxvo5l8pImEPhwTbhruImeRCSojTaJPS9U7bnjvj68/CFa + UWvf3IfKbkOLijQMQmzf9Q0AQwBolWgg3sJki7iigQKBgQCf82eve3W/s/pZzKGi + WWACcZLmDTHeH2AU3ZDfFaEAKObe/cdHMgk8MGewf1IF6QDQXtaxHlM5/FKQ1ohu + uoe7Xo1R+KlrVRxKAlNQ5lfzhAAgDNaOhpgkH4cehfPrIIh9rwNMSkHDRS0DELvY + DPyRumPy7zTg5YPzzl7tM1/OPA== + -----END PRIVATE KEY----- + + crt: | + -----BEGIN CERTIFICATE----- + MIIC6zCCAdOgAwIBAgIJAI4syJyPEWAMMA0GCSqGSIb3DQEBBQUAMAwxCjAIBgNV + BAMMASowHhcNMTgwNzI0MTE1MjQ0WhcNMTkwNzI0MTE1MjQ0WjAMMQowCAYDVQQD + DAEqMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvatxDBg7QzSgLQh8 + jNTH1lGiBrL+WZGu6X4yDii/yr60iFaWcsid5UgC3kcsgw0WXmMJG5DXQyYIqxZg + 9LyZGIn2FnxnSCZm43Zutixssw3+/VXvGkBdJS3HnTIaAn7u/qnIiGJ4x3b5MWOh + aPQk2T+5vqEjZlIx3SQ97HF+Jd76HQSuux6ZPltnhIcAMRuWhbLKQ5z4uC/YWipT + KbPnkp9YSyxmK5rYbT9mrLHJL3ci9dIUu/jjmRZo+b8RjW0J9heMIYrtOiZly6Dv + E/cnfFzTd/NxY0RGCo60HMiaN4s72sBIK0YvZjSjPQ4VrgXW2DXv3EoBn8ASuinP + XvMwiwIDAQABo1AwTjAdBgNVHQ4EFgQUK4SXDSeyVYbCWr31rz2K6GLRFoYwHwYD + VR0jBBgwFoAUK4SXDSeyVYbCWr31rz2K6GLRFoYwDAYDVR0TBAUwAwEB/zANBgkq + hkiG9w0BAQUFAAOCAQEAjz2PUbdi2S+h4UB3P2UBLdgDClkiSPF+gAqfw4D82faf + M8hpMuCcd3148dejU4tFPUdLx1MASK8ucCk7rcwVtafWPYU4nMDlmZ9Zj9F2Y8KY + dVfHfTIOblTSYc90g+nTFsTchkEFOH0nRZAKhCT3HphXNTZFNIQWoqe63SJZ8LTs + 8RBO/zcoh5E31+Rm0WxKlYH4QElLp9dXAtKueWGTafh2E8Re96IS+Uig+yC3RIYJ + MWLcATwR3lSnqN2ifByic5VGWbRKkGNsh3wAWlejL2FGv8mLU1q8nLK36UcU/HzZ + ziLtpidJOJHDpyDSAxDSxcP9fJ6gssMQln92DJ/SUQ== + -----END CERTIFICATE----- diff --git a/harness/attributes/docker-base.yml b/harness/attributes/docker-base.yml new file mode 100644 index 00000000..1b7f6843 --- /dev/null +++ b/harness/attributes/docker-base.yml @@ -0,0 +1,286 @@ +attributes: + services: + php-base: + environment: + HOST_OS_FAMILY: = @('host.os') + APP_NAME: = @('workspace.name') + APP_HOST: = @('hostname') + DB_PLATFORM: = @('database.platform') + DB_PLATFORM_VERSION: = @('database.platform_version') + DB_HOST: = @('database.host') + DB_PORT: = @('database.port') + DB_USER: = @('database.user') + DB_NAME: = @('database.name') + ELASTICSEARCH_HOST: = @('elasticsearch.host') + ELASTICSEARCH_PORT: = @('elasticsearch.port') + RABBITMQ_API_PORT: = @('rabbitmq.api_port') + RABBITMQ_EXTERNAL_HOST: = @('rabbitmq.external_host') + RABBITMQ_HOST: = @('rabbitmq.host') + RABBITMQ_PORT: = @('rabbitmq.port') + RABBITMQ_USER: = @('rabbitmq.user') + RABBITMQ_VHOST: = @('rabbitmq.vhosts.default') + REDIS_HOST: = @('redis.host') + REDIS_PORT: = @('redis.port') + REDIS_SESSION_HOST: = @('redis_session.host') + REDIS_SESSION_PORT: = @('redis_session.port') + SOLR_HOST: = @('services.solr.host') + SOLR_PORT: = @('services.solr.port') + SMTP_HOST: = @('smtp.host') + SMTP_PORT: = @('smtp.port') + PHP_IDE_CONFIG: "serverName=workspace" + TIDEWAYS_HOST: tideways + VARNISH_HOSTNAME_TEMPLATE: "varnish-%d.varnish-headless" + environment_secrets: + DB_PASS: = @('database.pass') + RABBITMQ_PASSWORD: = @('rabbitmq.password') + TIDEWAYS_APIKEY: "" + nginx: + image: = @('docker.repository') ~ ':' ~ @('app.version') ~ '-nginx' + publish: true + environment: + FPM_HOST: php-fpm + resources: + memory: "100Mi" + console: + enabled: true + image: = @('docker.repository') ~ ':' ~ @('app.version') ~ '-console' + publish: true + environment: + DB_ADMIN_USER: root + HAS_ELASTICSEARCH: "= @('services.elasticsearch.enabled') ? 'true' : 'false'" + HAS_VARNISH: "= @('services.varnish.enabled') ? 'true' : 'false'" + environment_secrets: + DB_ADMIN_PASS: = @('database.root_pass') + resources: + memory: "2048Mi" + cron: + enabled: "= 'cron' in @('app.services')" + image: = @('docker.repository') ~ ':' ~ @('app.version') ~ '-cron' + publish: "= @('services.cron.enabled')" + resources: + memory: "1024Mi" + php-fpm: + image: = @('docker.repository') ~ ':' ~ @('app.version') ~ '-php-fpm' + publish: true + environment: + AUTOSTART_PHP_FPM: "true" + resources: + memory: "1024Mi" + php-fpm-exporter: + image: hipages/php-fpm_exporter + environment: + PHP_FPM_SCRAPE_URI: = php_fpm_exporter_scrape_url('php-fpm', @('php-fpm.pools')) + resources: + memory: "100Mi" + blackfire: + enabled: "= 'blackfire' in @('app.services')" + image: blackfire/blackfire:latest + environment: + BLACKFIRE_AGENT_TIMEOUT: 10 + BLACKFIRE_LOG_LEVEL: 1 + environment_secrets: + BLACKFIRE_CLIENT_ID: "" + BLACKFIRE_CLIENT_TOKEN: "" + BLACKFIRE_SERVER_ID: "" + BLACKFIRE_SERVER_TOKEN: "" + elasticsearch: + enabled: "= 'elasticsearch' in @('app.services')" + image: = @('elasticsearch.image') ~ ':' ~ @('elasticsearch.tag') + resources: + memory: "1024Mi" + memcached: + enabled: "= 'memcached' in @('app.services')" + image: memcached:1-alpine + mysql: + enabled: "= 'mysql' in @('app.services')" + image: = @('mysql.image') ~ ':' ~ @('mysql.tag') + options: = @('database.var') + environment: + MYSQL_DATABASE: = @('database.name') + MYSQL_USER: = @('database.user') + environment_secrets: + MYSQL_PASSWORD: = @('database.pass') + MYSQL_ROOT_PASSWORD: = @('database.root_pass') + resources: + memory: "512Mi" + postgres: + enabled: "= 'postgres' in @('app.services')" + image: postgres:9.6 + environment: + POSTGRES_DB: = @('database.name') + POSTGRES_USER: = @('database.user') + PGDATA: /var/lib/postgresql/data/pgdata + environment_secrets: + POSTGRES_PASSWORD: = @('database.pass') + resources: + memory: "512Mi" + rabbitmq: + enabled: "= 'rabbitmq' in @('app.services')" + image: = @('rabbitmq.image') ~ ':' ~ @('rabbitmq.tag') + environment: + RABBITMQ_DEFAULT_USER: = @('rabbitmq.user') + RABBITMQ_DEFAULT_VHOST: = @('rabbitmq.vhosts.default') + environment_secrets: + RABBITMQ_DEFAULT_PASS: = @('rabbitmq.password') + RABBITMQ_ERLANG_COOKIE: = @('rabbitmq.erlang_cookie') + resources: + memory: "1024Mi" + redis: + enabled: "= 'redis' in @('app.services')" + image: redis:5-alpine + resources: + memory: "256Mi" + redis_session: + enabled: "= 'redis_session' in @('app.services')" + image: redis:5-alpine + resources: + memory: "1024Mi" + relay: + enabled: true + publish: false + solr: + enabled: "= 'solr' in @('app.services')" + config_path: "" + environment: + SOLR_CORE_NAME: collection1 + environment_secrets: {} + host: solr + image: = 'solr:' ~ @('services.solr.major_version') ~ '-slim' + major_version: 8 + port: 8983 + tideways: + enabled: "= 'tideways' in @('app.services')" + image: quay.io/inviqa_images/tideways:latest + environment: + TIDEWAYS_HOSTNAME: = @('hostname') + TIDEWAYS_ENV: production + resources: + memory: "256Mi" + varnish: + enabled: "= 'varnish' in @('app.services')" + image: varnish:6 + environment: + VARNISH_SIZE: "1024M" + resources: + memory: "1124Mi" + # webapp is by default two services combined, nginx and php-fpm + webapp: + enabled: true + pipeline: + base: + prometheus: + podMonitoring: false + services: + php-base: + environment: + APP_HOST: = @('pipeline.base.hostname') + DB_HOST: = '{{ .Values.resourcePrefix }}' ~ @('database.host') + ELASTICSEARCH_HOST: '{{ if .Values.service.elasticsearch | default .Values.docker.services.elasticsearch.enabled }}{{ .Values.resourcePrefix }}elasticsearch{{ end }}' + ES_HOST: '{{ if .Values.service.elasticsearch | default .Values.docker.services.elasticsearch.enabled }}{{ .Values.resourcePrefix }}elasticsearch:9200{{ end }}' + RABBITMQ_HOST: '{{ if .Values.service.rabbitmq | default .Values.docker.services.rabbitmq.enabled }}{{ .Values.resourcePrefix }}rabbitmq{{ end }}' + RABBITMQ_EXTERNAL_HOST: = @('pipeline.preview.rabbitmq.external_host') + REDIS_HOST: '{{ if .Values.service.redis | default .Values.docker.services.redis.enabled }}{{ .Values.resourcePrefix }}redis{{ end }}' + REDIS_SESSION_HOST: '{{ if .Values.service.redis_session | default .Values.docker.services.redis_session.enabled }}{{ .Values.resourcePrefix }}redis-session{{ end }}' + PHP_IDE_CONFIG: = '' + TIDEWAYS_HOST: "{{ .Values.resourcePrefix }}tideways" + TIDEWAYS_ENABLED: "{{ .Values.service.tideways | default .Values.docker.services.tideways.enabled }}" + VARNISH_HOSTNAME_TEMPLATE: "{{ .Values.resourcePrefix }}varnish-%d.{{ .Values.resourcePrefix }}varnish-headless" + mysql: + options: = @('services.mysql.options') + console: + environment: + TIDEWAYS_ENABLED: "= @('php.ext-tideways.cli.enable') ? '{{ .Values.service.tideways | default .Values.docker.services.tideways.enabled }}' : 'false'" + nginx: + environment: + FPM_HOST: localhost + ingress: + annotations: {} + metricsEnabled: false + metricsEndpoints: + - port: http + php-fpm-exporter: + environment: + PHP_FPM_SCRAPE_URI: = php_fpm_exporter_scrape_url('127.0.0.1', @('php-fpm.pools')) + metricsEnabled: true + metricsEndpoints: + - port: php-fpm-metrics + relay: + enabled: false + tideways: + environment: + TIDEWAYS_HOSTNAME: = @('pipeline.base.hostname') + istio: + gateways: + - "istio-system/{{ .Release.Namespace }}-gateway" + additionalGateways: [] + production: + # assumption is that in a production style environment these would be + # managed services outside of the applications control + services: + elasticsearch: + enabled: false + memcached: + enabled: false + mysql: + enabled: false + postgres: + enabled: false + redis: + enabled: false + redis_session: + enabled: false + qa: + services: + php-base: + environment: + APP_HOST: = @('pipeline.qa.hostname') + RABBITMQ_EXTERNAL_HOST: = @('pipeline.qa.rabbitmq.external_host') + SMTP_HOST: = @('pipeline.qa.smtp.host') + SMTP_PORT: = @('pipeline.qa.smtp.port') + tideways: + environment: + TIDEWAYS_HOSTNAME: = @('pipeline.qa.hostname') + preview: + resources: + memory: + app_init: "1024Mi" + app_migrate: "1024Mi" + services: + console: + enabled: false + resources: + memory: "1024Mi" + cron: + resources: + memory: "1024Mi" + elasticsearch: + resources: + memory: "1024Mi" + mysql: + resources: + memory: "512Mi" + nginx: + resources: + memory: "64Mi" + php-base: + environment: + SMTP_HOST: = @('pipeline.preview.smtp.host') + SMTP_PORT: = @('pipeline.preview.smtp.port') + php-fpm: + resources: + memory: "1024Mi" + php-fpm-exporter: + resources: + memory: "32Mi" + postgres: + resources: + memory: "512Mi" + redis: + resources: + memory: "64Mi" + redis_session: + resources: + memory: "64Mi" + tideways: + resources: + memory: "256Mi" diff --git a/harness/config/commands.yml b/harness/config/commands.yml new file mode 100644 index 00000000..5f08c37b --- /dev/null +++ b/harness/config/commands.yml @@ -0,0 +1,329 @@ + +command('enable'): + env: + USE_DOCKER_SYNC: = @('host.os') == 'darwin' and @('docker-sync') == 'yes' ? 'yes':'no' + USE_MUTAGEN: = @('host.os') == 'darwin' and @('mutagen') == 'yes' ? 'yes':'no' + APP_BUILD: = @('app.build') + APP_MODE: = @('app.mode') + NAMESPACE: = @('namespace') + HAS_ASSETS: = @('aws.bucket') !== null and @('aws.bucket') !== '' ? 'yes':'no' + COMPOSE_PROJECT_NAME: = @('namespace') + exec: | + #!bash(workspace:/) + source .my127ws/harness/scripts/enable.sh + +command('disable'): + env: + USE_DOCKER_SYNC: = (@('host.os') == 'darwin' and @('docker-sync') == 'yes') ? 'yes':'no' + USE_MUTAGEN: = @('host.os') == 'darwin' and @('mutagen') == 'yes' ? 'yes':'no' + NAMESPACE: = @('namespace') + COMPOSE_PROJECT_NAME: = @('namespace') + exec: | + #!bash(workspace:/) + source .my127ws/harness/scripts/disable.sh + +command('destroy'): + env: + NAMESPACE: = @('namespace') + APP_BUILD: = @('app.build') + APP_VERSION: = @('app.version') + DOCKER_REPOSITORY: = @('docker.repository') + USE_DOCKER_SYNC: = (@('host.os') == 'darwin' and @('docker-sync') == 'yes') ? 'yes':'no' + USE_MUTAGEN: = @('host.os') == 'darwin' and @('mutagen') == 'yes' ? 'yes':'no' + COMPOSE_PROJECT_NAME: = @('namespace') + exec: | + #!bash(workspace:/)|@ + source .my127ws/harness/scripts/destroy.sh + +command('networks external'): + env: + NETWORKS: = get_docker_external_networks() + exec: | + #!bash(workspace:/) + for NETWORK in ${NETWORKS}; do + if ! docker network inspect "${NETWORK}" >/dev/null 2>&1; then + passthru docker network create "${NETWORK}" + fi + done + +command('exec %'): + env: + COMPOSE_PROJECT_NAME: = @('namespace') + exec: | + #!bash(workspace:/)|= + if [ -t 0 ] && [ -t 1 ] ; then + docker-compose exec -u build console ={ input.argument('%') } + else + docker-compose exec -T -u build console ={ input.argument('%') } + fi + +command('logs %'): + env: + COMPOSE_PROJECT_NAME: = @('namespace') + exec: | + #!bash(harness:/)|= + docker-compose logs ={input.argument('%')} + +command('ps'): + env: + COMPOSE_PROJECT_NAME: = @('namespace') + exec: | + #!bash(workspace:/)|@ + docker-compose ps + +command('console'): + env: + COMPOSE_PROJECT_NAME: = @('namespace') + exec: | + #!bash(workspace:/)|@ + passthru docker-compose exec -u build console bash + +command('composer %'): + exec: | + #!bash(workspace:/)|= + passthru ws exec composer ={ input.argument('%') } + +command('db-console'): | + #!bash + ws db console + +command('db console'): + env: + COMPOSE_PROJECT_NAME: = @('namespace') + exec: | + #!bash(workspace:/)|@ + passthru "docker-compose exec console bash -c 'mysql --host \"\$DB_HOST\" --user \"\$DB_USER\" -p\"\$DB_PASS\" \"\$DB_NAME\"'" + +command('assets download'): + env: + AWS_ID: =@('aws.id') + AWS_KEY: =@('aws.key') + exec: | + #!bash(workspace:/)|@ + passthru ws.aws s3 sync '@('assets.remote')' '@('assets.local')' + +command('assets upload'): + env: + AWS_ID: =@('aws.id') + AWS_KEY: =@('aws.key') + exec: | + #!bash(workspace:/)|@ + passthru ws.aws s3 sync '@('assets.local')' '@('assets.remote')' + +command('feature docker-sync (on|off)'): + env: + ATTR_KEY: 'docker-sync' + ATTR_VAL: = input.command(3) == 'on' ? 'yes':'no' + exec: | + #!bash(workspace:/)|= + ws set $ATTR_KEY $ATTR_VAL + echo 'Updating docker-compose.yml' + run ws install --step=prepare + echo 'Bringing up the environment with the new setting' + if [[ "$ATTR_VAL" = "yes" ]]; then + passthru ws docker-sync start + fi + passthru ws enable + if [[ "$ATTR_VAL" = "no" ]]; then + passthru ws docker-sync stop + passthru ws docker-sync clean + fi + echo 'Done' + +command('frontend build'): + env: + COMPOSE_PROJECT_NAME: = @('namespace') + exec: | + #!bash(workspace:/)|@ + passthru docker-compose exec -u build console app build:frontend + +command('frontend watch'): + env: + COMPOSE_PROJECT_NAME: = @('namespace') + exec: | + #!bash(workspace:/)|@ + # Use `bash -i` to load up /home/build/.bashrc, which sets up node version manager (nvm) paths + docker-compose exec -u build --workdir '@('frontend.path')' console bash -i -c '@('frontend.watch')' + +command('frontend console'): + env: + COMPOSE_PROJECT_NAME: = @('namespace') + exec: | + #!bash(workspace:/)|@ + # Use `bash -i` to load up /home/build/.bashrc, which sets up node version manager (nvm) paths + passthru docker-compose exec -u build --workdir '@('frontend.path')' console bash -i + +command('port '): + env: + COMPOSE_PROJECT_NAME: = @('namespace') + exec: | + #!bash(workspace:/)|= + passthru docker port "$(docker-compose ps -q ={input.argument('service')})" + +command('service php-fpm restart'): + env: + COMPOSE_PROJECT_NAME: = @('namespace') + exec: | + #!bash(workspace:/)|@ + passthru ws install --step=prepare + docker-compose exec console bash -c 'cp -r /.my127ws/docker/image/console/root/usr/local/etc/php/conf.d/* /usr/local/etc/php/conf.d/' + docker-compose exec php-fpm bash -c 'cp -r /.my127ws/docker/image/php-fpm/root/usr/local/etc/php/conf.d/* /usr/local/etc/php/conf.d/' + passthru docker-compose exec php-fpm supervisorctl restart php-fpm + +command('set '): + env: + ATTR_KEY: = input.argument('attribute') + ATTR_VAL: = input.argument('value') + exec: | + #!bash(workspace:/)|= + if [ ! -f workspace.override.yml ]; then + touch workspace.override.yml + fi + if grep -q "attribute('${ATTR_KEY}'):" workspace.override.yml; then + echo "Removing old '${ATTR_KEY}' setting from workspace.override.yml" + sed "/^attribute('${ATTR_KEY}'): .*$/d" workspace.override.yml > workspace.override.yml.tmp && mv workspace.override.yml.tmp workspace.override.yml + fi + if grep -q "attribute('${ATTR_KEY}'):" workspace.override.yml; then + echo 'Could not remove line from workspace.override.yml, failing' + exit 1 + fi + echo "Setting '${ATTR_KEY}' setting to '${ATTR_VAL}' in workspace.override.yml" + echo "attribute('${ATTR_KEY}'): ${ATTR_VAL}" >> workspace.override.yml + +command('feature blackfire (on|off)'): + env: + ATTR_KEY: 'php.ext-blackfire.enable' + ATTR_VAL: = input.command(3) == 'on' ? 'yes':'no' + exec: | + #!bash(workspace:/)|= + ws set $ATTR_KEY $ATTR_VAL + echo 'Updating templates in .my127ws/' + run ws install --step=prepare + echo 'Bringing up php-fpm with the new setting' + run ws service php-fpm restart + echo 'Done' + +command('feature blackfire cli (on|off)'): + env: + ATTR_KEY: 'php.ext-blackfire.cli.enable' + ATTR_VAL: = input.command(4) == 'on' ? 'yes':'no' + exec: | + #!bash(workspace:/)|= + ws set $ATTR_KEY $ATTR_VAL + echo 'Updating templates in .my127ws/' + run ws install --step=prepare + echo 'Bringing up console with the new setting' + run ws service + +command('feature tideways (on|off)'): + env: + ATTR_KEY: 'php.ext-tideways.enable' + ATTR_VAL: = input.command(3) == 'on' ? 'yes':'no' + exec: | + #!bash(workspace:/)|= + ws set $ATTR_KEY $ATTR_VAL + echo 'Updating templates in .my127ws/' + run ws install --step=prepare + echo 'Bringing up php-fpm with the new setting' + run ws service php-fpm restart + echo 'Done' + +command('feature tideways cli (on|off)'): + env: + ATTR_KEY: 'php.ext-tideways.cli.enable' + ATTR_VAL: = input.command(4) == 'on' ? 'yes':'no' + exec: | + #!bash(workspace:/)|= + ws set $ATTR_KEY $ATTR_VAL + echo 'Updating templates in .my127ws/' + run ws install --step=prepare + echo 'Bringing up console with the new setting' + run ws service php-fpm restart + echo 'Done' + +command('feature tideways cli configure '): + env: + TIDEWAYS_SERVERKEY: = input.argument('server_key') + exec: | + #!bash(workspace:/)|= + echo "Importing Provided Tideways CLI Key (from https://app.tideways.io/user/cli-import-settings)" + docker-compose exec -T -u build console tideways import "$TIDEWAYS_SERVERKEY" + echo "Imported Tideways CLI key" + +command('feature xdebug (on|off)'): + env: + ATTR_KEY: 'php.ext-xdebug.enable' + ATTR_VAL: = input.command(3) == 'on' ? 'yes':'no' + exec: | + #!bash(workspace:/)|= + ws set $ATTR_KEY $ATTR_VAL + echo 'Updating templates in .my127ws/' + run ws install --step=prepare + echo 'Bringing up php-fpm with the new setting' + run ws service php-fpm restart + echo 'Done' + +command('feature xdebug cli (on|off)'): + env: + ATTR_KEY: 'php.ext-xdebug.cli.enable' + ATTR_VAL: = input.command(4) == 'on' ? 'yes':'no' + exec: | + #!bash(workspace:/)|= + ws set $ATTR_KEY $ATTR_VAL + echo 'Updating templates in .my127ws/' + run ws install --step=prepare + echo 'Bringing up console with the new setting' + run ws service php-fpm restart + echo 'Done' + +command('db import '): + env: + COMPOSE_PROJECT_NAME: = @('namespace') + DATABASE_FILE: = input.argument('database_file') + exec: | + #!bash(workspace:/)|= + passthru docker-compose exec -u build console app database:import "$DATABASE_FILE" + +command('harness update existing'): + env: + COMPOSE_PROJECT_NAME: = @('namespace') + exec: | + #!bash(workspace:/)|@ + ws disable + rm -rf .my127ws + ws install --step=download + ws harness prepare + touch .my127ws/.flag-built + ws refresh + ws exec app overlay:apply + ws exec composer install + ws exec app migrate + ws exec app welcome + +command('harness update fresh'): + env: + COMPOSE_PROJECT_NAME: = @('namespace') + exec: | + #!bash(workspace:/)|@ + ws disable || true + rm -rf .my127ws + ws install + +command('generate token '): + env: + LENGTH: = input.argument('length') + exec: | + #!php + $ascii_codes = range(48, 57) + range(97, 122) + range(65, 90); + $codes_length = (count($ascii_codes)-1); + shuffle($ascii_codes); + $string = ''; + for($i = 1; $i <= $env['LENGTH']; $i++) { + $previous_char = $char ?? ''; + $char = chr($ascii_codes[random_int(0, $codes_length)]); + while($char == $previous_char){ + $char = chr($ascii_codes[random_int(0, $codes_length)]); + } + $string .= $char; + } + echo $string; diff --git a/harness/config/docker-sync.yml b/harness/config/docker-sync.yml new file mode 100644 index 00000000..accbfab1 --- /dev/null +++ b/harness/config/docker-sync.yml @@ -0,0 +1,8 @@ +command('docker-sync (start|stop|clean)'): + env: + NAMESPACE: = @('namespace') + COMMAND: = input.command(2) + PATH: "$PATH:./.my127ws/" + exec: | + #!bash(workspace:/) + source .my127ws/harness/scripts/docker_sync.sh "$COMMAND" diff --git a/harness/config/events.yml b/harness/config/events.yml new file mode 100644 index 00000000..3b9ee0bc --- /dev/null +++ b/harness/config/events.yml @@ -0,0 +1,15 @@ + +after('harness.install'): | + #!bash + ws enable + +after('harness.refresh'): + env: + COMPOSE_PROJECT: = @('namespace') + exec: | + #!bash(workspace:/)|@ + run docker-compose stop + passthru "docker-compose config --services | grep -v php-fpm | xargs docker-compose pull" + passthru "docker-compose config --services | grep -v cron | grep -v job-queue-consumer | grep -v jenkins-runner | xargs docker-compose build --pull" + passthru "docker-compose config --services | grep -v cron | grep -v job-queue-consumer | grep -v jenkins-runner | xargs docker-compose up -d" + run docker-compose up -d --build diff --git a/harness/config/external-images.yml b/harness/config/external-images.yml new file mode 100644 index 00000000..2dadbc7c --- /dev/null +++ b/harness/config/external-images.yml @@ -0,0 +1,38 @@ +function('external_images', [services]): | + #!php + $upstreamImages = $producedImages = []; + $excludeImages = ['scratch']; + + foreach ($services as $service) { + if (count($service['upstream']) > 0) { + $upstreamImages = array_merge($upstreamImages, $service['upstream']); + if ($service['image']) { + $producedImages[] = $service['image']; + } + } else if ($service['image']) { + $upstreamImages[] = $service['image']; + } + } + $externalImages = array_diff($upstreamImages, $producedImages, $excludeImages); + + # workspace commands don't allow non-string types + = join(' ', $externalImages); + + +command('external-images config'): + env: + IMAGES: = external_images(docker_service_images()) + exec: | + #!php + $compose = ['version' => '3', 'services' => []]; + foreach (explode(' ', $env['IMAGES']) as $image) { + $compose['services'][str_replace(['/', ':'], '_', $image)] = ['image' => $image]; + } + echo \Symfony\Component\Yaml\Yaml::dump($compose, 100, 2); + +command('external-images pull'): + env: + BASE_IMAGES: = external_images(docker_service_images()) + exec: | + #!bash(workspace:/)|@ + passthru 'ws external-images config | docker-compose -f - pull' diff --git a/harness/config/functions.yml b/harness/config/functions.yml new file mode 100644 index 00000000..c0116069 --- /dev/null +++ b/harness/config/functions.yml @@ -0,0 +1,209 @@ +function('to_yaml', [data]): | + #!php + $yaml = \Symfony\Component\Yaml\Yaml::dump($data, 100, 2)); + if (is_array($data) && count($data) > 0) { + $yaml = "\n" . rtrim(preg_replace('/^/m', ' ', $yaml), "\n"); + } + = $yaml; + +function('to_nice_yaml', [data, indentation, nesting]): | + #!php + $yaml = \Symfony\Component\Yaml\Yaml::dump($data, 100, $indentation ?: 2); + if (is_array($data) && count($data) > 0) { + $yaml = "\n" . rtrim(preg_replace('/^/m', str_repeat(' ', $nesting ?: 2), $yaml), "\n"); + } + = $yaml; + +function('indent', [text, indentation]): | + #!php + = preg_replace('/^/m', str_repeat(' ', $indentation ?: 2), $text); + +function('deep_merge', [arrays]): | + #!php + // source https://api.drupal.org/api/drupal/includes%21bootstrap.inc/function/drupal_array_merge_deep_array/7.x + $deepMerge = function ($arrays) use (&$deepMerge) { + $result = array(); + foreach ($arrays as $array) { + if ($array === null) { continue; } + foreach ($array as $key => $value) { + // Renumber integer keys as array_merge_recursive() does. Note that PHP + // automatically converts array keys that are integer strings (e.g., '1') + // to integers. + if (is_integer($key)) { + $result[] = $value; + } + elseif (isset($result[$key]) && is_array($result[$key]) && is_array($value)) { + $result[$key] = $deepMerge(array( + $result[$key], + $value, + )); + } + else { + $result[$key] = $value; + } + } + } + return $result; + }; + = $deepMerge($arrays); + +function('deep_merge_to_yaml', [arrays, indentation, nesting]): | + #!php + trigger_error('deep_merge_to_yaml is deprecated, please use separate deep_merge and to_nice_yaml functions', E_USER_DEPRECATED); + // source https://api.drupal.org/api/drupal/includes%21bootstrap.inc/function/drupal_array_merge_deep_array/7.x + $deepMerge = function ($arrays) use (&$deepMerge) { + $result = array(); + foreach ($arrays as $array) { + if ($array === null) { continue; } + foreach ($array as $key => $value) { + // Renumber integer keys as array_merge_recursive() does. Note that PHP + // automatically converts array keys that are integer strings (e.g., '1') + // to integers. + if (is_integer($key)) { + $result[] = $value; + } + elseif (isset($result[$key]) && is_array($result[$key]) && is_array($value)) { + $result[$key] = $deepMerge(array( + $result[$key], + $value, + )); + } + else { + $result[$key] = $value; + } + } + } + return $result; + }; + $text = $deepMerge($arrays); + = preg_replace('/^/m', str_repeat(' ', $nesting ?: 2), \Symfony\Component\Yaml\Yaml::dump($text, 100, $indentation ?: 2)); + +function('filter_local_services', [services]): | + #!php + $filteredServices = []; + foreach ($services as $serviceName => $service) { + $filteredService = []; + foreach ($service as $key => $value) { + switch ($key) { + case 'enabled': + case 'environment': + case 'image': + case 'resources': + $filteredService[$key] = $value; + } + } + if (count($filteredService) > 0) { + $filteredServices[$serviceName] = $filteredService; + } + } + = $filteredServices; + +function('get_docker_external_networks'): | + #!php + $configRaw = shell_exec('docker-compose config'); + $config = \Symfony\Component\Yaml\Yaml::parse($configRaw); + $externalNetworks = []; + if (isset($config['networks'])) { + foreach ($config['networks'] as $network) { + if (isset($network['external'])) { + if (is_array($network['external'])) { + $externalNetworks[] = $network['external']['name']; + } else if ($network['external'] === true) { + $externalNetworks[] = $network['name']; + } + } + } + } + = join(" ", $externalNetworks); + +function('docker_service_images'): | + #!php + $configRaw = shell_exec('docker-compose config'); + $config = \Symfony\Component\Yaml\Yaml::parse($configRaw); + $images = []; + + foreach ($config['services'] as $serviceName => $service) { + $image = [ + 'image' => $service['image'] ?? null, + 'upstream' => [], + ]; + + if (isset($service['build'])) { + $context = rtrim($service['build']['context'], '/'); + $dockerfile = $service['build']['dockerfile'] ?? 'Dockerfile'; + + if (preg_match_all('/^FROM\s+([^\s]*)/m', file_get_contents($context.'/'.$dockerfile), $matches) === false) { + continue; + } + $image['upstream'] = $matches[1]; + } + $images[$serviceName] = $image; + } + + = $images; + +function('get_docker_registry', [dockerRepository]): | + #!php + $dockerRepoParts = explode('/', $dockerRepository); + if (strpos($dockerRepoParts[0], '.') !== false) { + $registry = $dockerRepoParts[0]; + } + = $registry ?? 'https://index.docker.io/v1/'; + +function('docker_config', [registryConfig]): | + #!php + $config = [ + 'auths' => [ + $registryConfig['url'] => [ + 'auth' => base64_encode($registryConfig['username'].':'.$registryConfig['password']) + ] + ] + ]; + + = json_encode($config); + +function('branch'): | + #!bash(workspace:/) + =$(git branch | grep \* | cut -d ' ' -f2) + +function('slugify', [text]): | + #!php + $text = preg_replace('~[^\pL\d]+~u', '-', $text); + $text = iconv('utf-8', 'us-ascii//TRANSLIT', $text); + $text = preg_replace('~[^-\w]+~', '', $text); + $text = trim($text, '-'); + $text = preg_replace('~-+~', '-', $text); + $text = strtolower($text); + = $text; + +function('php_fpm_exporter_scrape_url', [hostname, pools]): | + #!php + $text = join( + ',', + array_map( + function ($pool) use ($hostname) { + return 'tcp://' . $hostname .':' . $pool['port'] . '/status'; + }, + $pools + ) + ); + = $text; + +function('publishable_services', [services]): | + #!php + $pushServices = array_map( + function ($serviceName, $service) { + return ($service['publish'] ?? false) ? $serviceName : null; + }, + array_keys($services), + $services + ); + = join(' ', array_filter($pushServices)); + +function('version_compare', [version1, version2, operator]): | + #!php + $count1 = substr_count($version1, '.'); + $count2 = substr_count($version2, '.'); + $version1 .= str_repeat('.0', max(0, $count2 - $count1)); + $version2 .= str_repeat('.0', max(0, $count1 - $count2)); + = version_compare($version1, $version2, $operator); diff --git a/harness/config/mutagen.yml b/harness/config/mutagen.yml new file mode 100644 index 00000000..a9188296 --- /dev/null +++ b/harness/config/mutagen.yml @@ -0,0 +1,103 @@ +function('get_mutagen_volume_names'): | + #!php + $volumeNames = []; + + if (file_exists('mutagen.yml')) { + $configRaw = file_get_contents('mutagen.yml'); + $config = \Symfony\Component\Yaml\Yaml::parse($configRaw); + + if (isset($config['sync'])) { + foreach (array_keys($config['sync']) as $syncName) { + $volumeNames[] = $syncName . '-sync'; + } + } + } + = $volumeNames; + +function('get_mutagen_volume_containers'): | + #!php + $volumeContainers = []; + + if (file_exists('mutagen.yml')) { + $configRaw = file_get_contents('mutagen.yml'); + $config = \Symfony\Component\Yaml\Yaml::parse($configRaw); + + if (isset($config['sync'])) { + foreach ($config['sync'] as $syncConfig) { + $parts = parse_url($syncConfig['beta']); + $volumeContainers[] = $parts['host']; + } + } + } + = join("\n", array_unique($volumeContainers)); + +function('get_mutagen_volume_mappings'): | + #!php + $volumeMappings = []; + + if (file_exists('mutagen.yml')) { + $configRaw = file_get_contents('mutagen.yml'); + $config = \Symfony\Component\Yaml\Yaml::parse($configRaw); + + if (isset($config['sync'])) { + foreach ($config['sync'] as $syncName => $syncConfig) { + $parts = parse_url($syncConfig['beta']); + $volumeMappings[] = $parts['host'] . ':' . $syncName . '-sync:' . $parts['path']; + } + } + } + = join("\n", $volumeMappings); + +command('mutagen (start|stop|pause|resume)'): + env: + COMMAND: = input.command(2) + CONTAINER_NAMES: = get_mutagen_volume_containers() + VOLUME_MAPPINGS: = get_mutagen_volume_mappings() + exec: | + #!bash(workspace:/) + source .my127ws/harness/scripts/mutagen.sh "$COMMAND" + +command('mutagen rm'): + env: + CONTAINER_NAMES: = get_mutagen_volume_containers() + exec: | + #!bash(workspace:/) + CONTAINER_NAMES=($CONTAINER_NAMES) + passthru docker volume rm "${CONTAINER_NAMES[@]}" + +command('switch (cached-volumes|delegated-volumes|mutagen|docker-sync)'): + env: + SYNC: = input.command(2) + CONTAINER_NAMES: = get_mutagen_volume_containers() + exec: | + #!bash(workspace:/)|= + run ws disable + if [[ "$SYNC = "delegated-volumes" ]]; then + ws set delegated-volumes yes + ws set mutagen no + ws set docker-sync no + elif [[ "$SYNC" = "mutagen" ]]; then + ws set delegated-volumes no + ws set mutagen yes + ws set docker-sync no + elif [[ "$SYNC" = "docker-sync" ]]; then + ws set delegated-volumes no + ws set mutagen no + ws set docker-sync yes + else + ws set delegated-volumes no + ws set mutagen no + ws set docker-sync no + fi + run ws harness prepare + echo 'Bringing up the environment with the new setting' + if [[ "$SYNC" = "mutagen" ]]; then + if command -v docker-sync >/dev/null 2>&1 && [ -f docker-sync.yml ]; then + passthru ws docker-sync clean + fi + passthru ws mutagen start + else + passthru ws mutagen stop + fi + passthru ws enable + echo 'Done' diff --git a/harness/config/pipeline.yml b/harness/config/pipeline.yml new file mode 100644 index 00000000..d899730e --- /dev/null +++ b/harness/config/pipeline.yml @@ -0,0 +1,120 @@ + +command('app build'): + env: + HAS_CRON: "= @('services.cron.enabled') ? 'true' : 'false'" + HAS_JENKINS_RUNNER: "= @('services.jenkins-runner.enabled') ? 'true' : 'false'" + exec: | + #!bash(workspace:/)|@ + ws external-images pull + + # dependency ordered build + passthru docker-compose build console + passthru docker-compose build php-fpm nginx + if [[ "${HAS_CRON}" == "true" ]]; then + passthru docker-compose build cron + fi + if [[ "${HAS_JENKINS_RUNNER}" == "true" ]]; then + passthru docker-compose build jenkins-runner + fi + +command('app build '): + env: + SERVICE: = input.argument('service') + exec: | + #!bash(workspace:/)|@ + passthru docker-compose build "${SERVICE}" + +command('app publish'): + env: + COMPOSE_HTTP_TIMEOUT: 180 + DOCKER_CLIENT_TIMEOUT: 180 + exec: | + #!bash(workspace:/)|@ + echo '@('docker.registry.password')' | run docker login --username='@('docker.registry.username')' --password-stdin '@('docker.registry.url')' + passthru docker-compose push @('pipeline.publish.services') + run docker logout '@('docker.registry.url')' + +command('app publish chart '): + env: + SSH_PRIVATE_KEY: = @('pipeline.publish.chart.git.ssh_private_key') + REPOSITORY: = @('pipeline.publish.chart.git.repository') + ARTIFACTS_PATH: = "./build-artifacts-repository/" ~ @('pipeline.publish.chart.git.path') ~ "/" ~ input.argument('release') + MESSAGE: = input.argument('message') + USER_EMAIL: = @('pipeline.publish.chart.git.email') + exec: | + #!bash(workspace:/)|@ + + run rm -rf build-artifacts-repository + echo "${SSH_PRIVATE_KEY}" | base64 -d > id_rsa + chmod 0600 id_rsa + + export GIT_SSH_COMMAND='ssh -i ./id_rsa -o "IdentitiesOnly yes" -F /dev/null -o StrictHostKeyChecking=no' + + run git clone "$REPOSITORY" ./build-artifacts-repository + run git -C ./build-artifacts-repository config user.email "${USER_EMAIL}" + + run mkdir -p $ARTIFACTS_PATH + run rsync --exclude='*.twig' --exclude='_twig' --delete -a .my127ws/helm/app/ "${ARTIFACTS_PATH}/" + + export GIT_SSH_COMMAND='ssh -i ../id_rsa -o "IdentitiesOnly yes" -F /dev/null -o StrictHostKeyChecking=no' + run git -C ./build-artifacts-repository add . + run "git -C ./build-artifacts-repository commit --allow-empty -m '${MESSAGE}'" + run git -C ./build-artifacts-repository push origin -u HEAD + +command('app deploy '): + env: + ENVIRONMENT: = input.argument('environment') + NAMESPACE: = @('pipeline.' ~ input.argument('environment') ~ '.namespace') + CLUSTER: = @('pipeline.' ~ input.argument('environment') ~ '.cluster.name') + TIMEOUT: = @('helm.timeout') + exec: | + #!bash(harness:/helm)|= + set -o pipefail + cd "${ENVIRONMENT}" + doctl -t "$DO_ACCESS_TOKEN" kubernetes cluster kubeconfig show "$CLUSTER" > kubectl.config.yaml + if helm version --short --client | grep '^Client: v2' >/dev/null 2>&1; then + passthru helm init --client-only + fi + passthru helm dependency build + passthru helm --kubeconfig="${PWD}/kubectl.config.yaml" upgrade --wait --atomic --install --timeout "${TIMEOUT}" --namespace "${NAMESPACE}" "${NAMESPACE}" ./ + +command('helm template '): + env: + CHART_PATH: = input.argument('chart-path') + NAMESPACE: = @('pipeline.' ~ input.argument('environment') ~ '.namespace') + exec: | + #!bash(harness:/helm)|= + set -o pipefail + cd "${CHART_PATH}" + if helm version --short --client | grep '^Client: v2' >/dev/null 2>&1; then + passthru helm init --client-only + fi + passthru helm dependency build + passthru helm template . + +command('helm kubeval '): + env: + CHART_PATH: = input.argument('chart-path') + NAMESPACE: = @('pipeline.' ~ input.argument('environment') ~ '.namespace') + ADDITIONAL_SCHEMA_LOCATIONS: = @('helm.additional_schema_locations') + exec: | + #!bash(harness:/helm)|= + set -o pipefail + cd "${CHART_PATH}" + if helm version --short --client | grep '^Client: v2' >/dev/null 2>&1; then + passthru helm init --client-only + fi + passthru helm dependency build + + if readlink "${HELM_HOME:-$HOME}/.helm/plugins/helm-kubeval" | grep '/https-github.com-instrumenta-helm-kubeval$' >/dev/null; then + passthru helm plugin remove kubeval + fi + + passthru helm plugin install https://github.com/inviqa/helm-kubeval || true + KUBEVAL_OPTS=() + + if [ -n "${ADDITIONAL_SCHEMA_LOCATIONS:-}" ]; then + KUBEVAL_OPTS+=(--additional-schema-locations "${ADDITIONAL_SCHEMA_LOCATIONS}") + fi + + passthru helm kubeval "${KUBEVAL_OPTS[@]}" . diff --git a/harness/config/secrets.yml b/harness/config/secrets.yml new file mode 100644 index 00000000..89a34f9c --- /dev/null +++ b/harness/config/secrets.yml @@ -0,0 +1,125 @@ +command('secret image-pull-config [--cert=] [--scope=] [--namespace=]'): + env: + SEALED_SECRETS: "= @('helm.feature.sealed_secrets') ? 'yes' : 'no'" + DEFAULT_CONFIG: = docker_config(@('docker.registry')) + SEALED_SECRETS_CONTROLLER_NAME: = @('helm.sealed_secrets.controller_name') + SEALED_SECRETS_CONTROLLER_NAMESPACE: = @('helm.sealed_secrets.controller_namespace') + SEALED_SECRETS_CERTIFICATE_FILE: "= input.option('cert') ?: @('helm.sealed_secrets.certificate_file')" + SECRET_NAMESPACE: "= input.option('namespace') ?: @('helm.sealed_secrets.namespace')" + SECRET_SCOPE: "= input.option('scope') ?: @('helm.sealed_secrets.scope')" + exec: | + #!bash + if [ "$SEALED_SECRETS" == 'yes' ] && ! command -v kubeseal >/dev/null; then + echo 'kubeseal is needed in order to use this command' >&2 + exit 1 + fi + + if [ -t 0 ] ; then + # Use an editor with a temp file to allow longer terminal input + TMPFILE="$(mktemp -t tmp.XXXXXXXXX)" + "${EDITOR:-vi}" "${TMPFILE}" + DOCKER_CONFIG="$(cat "${TMPFILE}")" + rm -f "${TMPFILE}" + else + # read from stdin until EOF + DOCKER_CONFIG="$(cat)" + fi + + DOCKER_CONFIG="${DOCKER_CONFIG:-${DEFAULT_CONFIG}}" + + if [ "$SEALED_SECRETS" == 'yes' ]; then + echo 'Encrypting as a sealed-secret value with certificate from current kubectl context' >&2 + DEFAULT_SCOPE=cluster-wide + KUBESEAL_OPTS=( + --name "image-pull-config" + ) + if [ -n "${SEALED_SECRETS_CONTROLLER_NAME:-}" ]; then + KUBESEAL_OPTS+=( + --controller-name "${SEALED_SECRETS_CONTROLLER_NAME}" + ) + fi + if [ -n "${SEALED_SECRETS_CONTROLLER_NAMESPACE:-}" ]; then + KUBESEAL_OPTS+=( + --controller-namespace "${SEALED_SECRETS_CONTROLLER_NAMESPACE}" + ) + fi + if [ -n "${SEALED_SECRETS_CERTIFICATE_FILE:-}" ]; then + KUBESEAL_OPTS+=( + --cert "${SEALED_SECRETS_CERTIFICATE_FILE}" + ) + fi + if [ -n "${SECRET_NAMESPACE:-}" ]; then + DEFAULT_SCOPE=namespace-wide + KUBESEAL_OPTS+=(--namespace "$SECRET_NAMESPACE") + fi + KUBESEAL_OPTS+=(--scope "${SECRET_SCOPE:-$DEFAULT_SCOPE}") + + echo -n "${DOCKER_CONFIG}" | passthru kubeseal --raw "${KUBESEAL_OPTS[@]}" + else + echo 'Note: this has unencrypted credentials in, do not save directly to file' >&2 + echo "If storing within workspace attributes, use `ws secret encrypt` first" >&2 + echo "${DOCKER_CONFIG}" | base64 + fi + +command('sealed-secret encrypt (string|blob) [--cert=] [--scope=] [--namespace=] '): + env: + INPUT_TYPE: = input.command(3) + SEALED_SECRETS_CONTROLLER_NAME: = @('helm.sealed_secrets.controller_name') + SEALED_SECRETS_CONTROLLER_NAMESPACE: = @('helm.sealed_secrets.controller_namespace') + SEALED_SECRETS_CERTIFICATE_FILE: "= input.option('cert') ?: @('helm.sealed_secrets.certificate_file')" + SECRET_NAME: = input.argument('secret-name') + SECRET_NAMESPACE: "= input.option('namespace') ?: @('helm.sealed_secrets.namespace')" + SECRET_SCOPE: "= input.option('scope') ?: @('helm.sealed_secrets.scope')" + exec: | + #!bash + if ! command -v kubeseal >/dev/null; then + echo 'kubeseal is needed in order to use this command' >&2 + exit 1 + fi + + echo "Enter the secret ${INPUT_TYPE} to encrypt" >&2 + case "${INPUT_TYPE}" in + string) + read DATA # read a single line + ;; + blob) + if [ -t 0 ] ; then + # Use an editor with a temp file to allow longer terminal input + TMPFILE="$(mktemp -t tmp.XXXXXXXXX)" + "${EDITOR:-vi}" "${TMPFILE}" + DATA="$(cat "${TMPFILE}")" + rm -f "${TMPFILE}" + else + # read from stdin until EOF + DATA="$(cat)" + fi + ;; + esac + + echo 'Encrypting as a sealed-secret value with certificate from current kubectl context' >&2 + DEFAULT_SCOPE=cluster-wide + KUBESEAL_OPTS=( + --name "${SECRET_NAME}" + ) + if [ -n "${SEALED_SECRETS_CONTROLLER_NAME:-}" ]; then + KUBESEAL_OPTS+=( + --controller-name "${SEALED_SECRETS_CONTROLLER_NAME}" + ) + fi + if [ -n "${SEALED_SECRETS_CONTROLLER_NAMESPACE:-}" ]; then + KUBESEAL_OPTS+=( + --controller-namespace "${SEALED_SECRETS_CONTROLLER_NAMESPACE}" + ) + fi + if [ -n "${SEALED_SECRETS_CERTIFICATE_FILE:-}" ]; then + KUBESEAL_OPTS+=( + --cert "${SEALED_SECRETS_CERTIFICATE_FILE}" + ) + fi + if [ -n "${SECRET_NAMESPACE:-}" ]; then + DEFAULT_SCOPE=namespace-wide + KUBESEAL_OPTS+=(--namespace "$SECRET_NAMESPACE") + fi + KUBESEAL_OPTS+=(--scope "${SECRET_SCOPE:-$DEFAULT_SCOPE}") + + echo -n "${DATA}" | passthru kubeseal --raw "${KUBESEAL_OPTS[@]}" diff --git a/harness/scripts/destroy.sh b/harness/scripts/destroy.sh new file mode 100755 index 00000000..a95f28a3 --- /dev/null +++ b/harness/scripts/destroy.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +run docker-compose down --rmi local --volumes --remove-orphans + +if [[ "$USE_DOCKER_SYNC" = "yes" ]] && [ -f docker-sync.yml ]; then + run ws docker-sync clean + run docker volume rm "${NAMESPACE}-sync" +elif [[ "$USE_MUTAGEN" = "yes" ]]; then + run ws mutagen stop + passthru ws mutagen rm +fi + +if [[ "$APP_BUILD" = "static" ]]; then + run "docker images --filter=since='${DOCKER_REPOSITORY}:${APP_VERSION}-console' -q | xargs --no-run-if-empty docker image rm --force" + run "docker images --filter=reference='${DOCKER_REPOSITORY}:${APP_VERSION}-*' -q | xargs --no-run-if-empty docker image rm --force" + run "docker images --filter=reference='${NAMESPACE}-*:dev' -q | xargs --no-run-if-empty docker image rm --force" +fi + +run rm -f .my127ws/.flag-built diff --git a/harness/scripts/disable.sh b/harness/scripts/disable.sh new file mode 100755 index 00000000..632d0298 --- /dev/null +++ b/harness/scripts/disable.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +if [[ "$USE_DOCKER_SYNC" = "yes" ]] && [ -f docker-sync.yml ]; then + run ws docker-sync stop +elif [[ "$USE_MUTAGEN" = "yes" ]]; then + run ws mutagen pause +fi + +run docker-compose stop diff --git a/harness/scripts/docker_sync.sh b/harness/scripts/docker_sync.sh new file mode 100644 index 00000000..2a0cb135 --- /dev/null +++ b/harness/scripts/docker_sync.sh @@ -0,0 +1,84 @@ +#!/usr/bin/env bash + +set -e -o pipefail + +if [ "$#" -ne 1 ]; then + echo "This script supports only one parameter" + exit 1 +fi + +COMMAND="$1" +PATH="$PATH:./.my127ws/utilities/rbenv/bin/" + +install_rbenv() +( + if command -v rbenv > /dev/null 2>&1; then + return 0 + fi + + if command -v sw_vers > /dev/null 2>&1 && sw_vers | grep -q Mac && command -v brew > /dev/null 2>&1; then + passthru brew install rbenv + else + mkdir -p .my127ws/utilities/ + if [ ! -d .my127ws/utilities/rbenv ]; then + git clone https://github.com/rbenv/rbenv.git .my127ws/utilities/rbenv + fi + mkdir -p "$(rbenv root)"/plugins + git clone https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ruby-build + fi + + passthru rbenv install --skip-existing 2.7.0 + run rbenv local 2.7.0 + init_rbenv +) + +init_rbenv() +{ + eval "$(rbenv init -)" +} + +install_docker_sync() +( + if command -v docker-sync > /dev/null 2>&1; then + return 0 + fi + + install_rbenv + passthru gem install docker-sync --no-document +) + +start() +{ + install_docker_sync + init_rbenv + passthru docker-sync start +} + +stop() +{ + init_rbenv + passthru docker-sync stop +} + +clean() +{ + init_rbenv + run docker-sync stop + run docker rm "${NAMESPACE}-sync" +} + +case "$COMMAND" in + start) + start + ;; + stop) + stop + ;; + clean) + clean + ;; + *) + echo "Command not supported" + exit 1 + ;; +esac diff --git a/harness/scripts/enable.sh.twig b/harness/scripts/enable.sh.twig new file mode 100755 index 00000000..c44a7382 --- /dev/null +++ b/harness/scripts/enable.sh.twig @@ -0,0 +1,85 @@ +#!/usr/bin/env bash + +main() +{ + passthru ws networks external + if [ ! -f .my127ws/.flag-built ]; then + + passthru docker-compose down + + if [[ "$HAS_ASSETS" = "yes" ]]; then + ws assets download + fi + + $APP_BUILD + touch .my127ws/.flag-built + + else + passthru docker-compose up -d + passthru docker-compose exec -T -u build console app welcome + fi + + if [[ "$APP_BUILD" = "dynamic" && "$USE_DOCKER_SYNC" = "yes" ]]; then + passthru ws docker-sync start + elif [[ "$APP_BUILD" = "dynamic" && "$USE_MUTAGEN" = "yes" ]]; then + passthru ws mutagen resume + fi +} + +dynamic() +{ + # we synchronise then stop docker-sync as leaving it running during the build + # will often cause it to crash. + + if [[ "$USE_DOCKER_SYNC" = "yes" ]]; then + passthru ws docker-sync start + passthru ws docker-sync stop + elif [[ "$USE_MUTAGEN" = "yes" ]]; then + passthru ws mutagen start + passthru ws mutagen pause + fi + + ws external-images pull + + passthru "docker-compose config --services | grep -v cron | grep -v jenkins-runner | xargs docker-compose build" + + {% if @('services.cron.enabled') %} + passthru docker-compose build cron + {% endif %} + {% if @('services.jenkins-runner.enabled') %} + passthru docker-compose build jenkins-runner + {% endif %} + + # Bring up console to fix file permissions + passthru docker-compose up -d console + + # Bring up all services apart from cron and jenkins-runner + passthru "docker-compose config --services | grep -v cron | grep -v jenkins-runner | xargs docker-compose up -d" + + passthru docker-compose exec -T -u build console app build + passthru docker-compose exec -T -u build console app init + + # Bring up all services + passthru docker-compose up -d +} + +static() +{ + ws app build + + {% if @('services.cron.enabled') %} + # Bring up all but cron + passthru "docker-compose config --services | grep -v cron | xargs docker-compose up -d" + {% else %} + # Bring up all services + passthru docker-compose up -d + {% endif %} + + passthru docker-compose exec -T -u build console app init + + {% if @('services.cron.enabled') %} + passthru docker-compose up -d cron + {% endif %} +} + +main diff --git a/harness/scripts/latest-mutagen-release.php b/harness/scripts/latest-mutagen-release.php new file mode 100644 index 00000000..b5ace9cc --- /dev/null +++ b/harness/scripts/latest-mutagen-release.php @@ -0,0 +1,33 @@ + [ + 'header' => "User-Agent: inviqa/harness-base-php\r\n", + ], +]); +$releases = file_get_contents('https://api.github.com/repos/mutagen-io/mutagen/releases', false, $fetchOptions); +if (!$releases) { + throw new Exception('Could not fetch releases. Response from GitHub: ' . $releases); +} + +$jsonReleases = json_decode($releases, true); +if (!$jsonReleases) { + throw new Exception('Could not decode releases. Response from GitHub: ' . $releases); +} + +$stableReleases = array_filter($jsonReleases, function ($release) { + return !$release['prerelease'] && !$release['draft']; +}); +$latestStableRelease = reset($stableReleases); +if (!$latestStableRelease) { + throw new Exception('Could not find latest stable release.'); +} + +$osFamily = strtolower(PHP_OS_FAMILY); +$releaseAssets = array_filter($latestStableRelease['assets'], function ($asset) use ($osFamily) { + return preg_match("/^mutagen_.*${osFamily}.*amd64.*/", $asset['name']) > 0; +}); +$releaseAsset = reset($releaseAssets); +if (!$releaseAsset) { + throw new Exception('Could not find latest stable release asset for your OS Platform: ' . $osFamily); +} +echo $releaseAsset['browser_download_url']; diff --git a/harness/scripts/mutagen.sh b/harness/scripts/mutagen.sh new file mode 100644 index 00000000..607b9e43 --- /dev/null +++ b/harness/scripts/mutagen.sh @@ -0,0 +1,112 @@ +#!/usr/bin/env bash + +set -o errexit +set -o nounset +set -o pipefail + +if [ "$#" -ne 1 ]; then + echo "This script supports only one parameter" + exit 1 +fi + +COMMAND="$1" +PATH="$PATH:./.my127ws/utilities/mutagen/" + +# shellcheck disable=SC2206 +CONTAINER_NAMES=($CONTAINER_NAMES) + +install_mutagen() +{ + if command -v mutagen > /dev/null 2>&1; then + return 0 + fi + + if command -v sw_vers > /dev/null 2>&1 && sw_vers | grep -q Mac && command -v brew > /dev/null 2>&1; then + passthru brew install mutagen-io/mutagen/mutagen + return "$?" + fi + mkdir -p .my127ws/utilities/mutagen/ + local download_url="" + download_url="$(php .my127ws/harness/scripts/latest-mutagen-release.php)" + if [ -z "$download_url" ]; then + echo "Failed to get mutagen download link. Please install mutagen globally." + return 1 + fi + + run curl -L -q -sS -f "$download_url" -o .my127ws/utilities/mutagen/mutagen.tar.gz + run "cd .my127ws/utilities/mutagen/ && tar -xf mutagen.tar.gz" +} + +setup_sync_container() +{ + local CONTAINER_NAME + local CONTAINER_VOLUME_MAPPINGS + local line + for CONTAINER_NAME in "${CONTAINER_NAMES[@]}"; do + if [[ "$(docker ps -a -f "name=${CONTAINER_NAME}" --format '{{.Names}}')" == "${CONTAINER_NAME}" ]]; then + passthru docker rm -f "${CONTAINER_NAME}" + fi + + CONTAINER_VOLUME_MAPPINGS=() + while IFS= read -r line; do + CONTAINER_VOLUME_MAPPINGS+=("$line") + done < <(echo "${VOLUME_MAPPINGS}" | grep "^${CONTAINER_NAME}" | cut -d ':' -f2- ) + + # shellcheck disable=SC2046 + passthru docker run -d --name "${CONTAINER_NAME}" $(printf -- '-v %q ' "${CONTAINER_VOLUME_MAPPINGS[@]}") alpine:latest tail -f /dev/null + done +} + +start_mutagen_daemon() +{ + passthru mutagen daemon start +} + +start() +{ + install_mutagen + setup_sync_container + start_mutagen_daemon + + mutagen project list > /dev/null 2>&1 && passthru mutagen project terminate + passthru mutagen project start + passthru mutagen project flush +} + +stop() +{ + passthru mutagen project terminate + passthru docker rm -f "${CONTAINER_NAMES[@]}" +} + +pause() +{ + passthru mutagen project pause + passthru docker stop "${CONTAINER_NAMES[@]}" +} + +resume() +{ + start_mutagen_daemon + passthru docker start "${CONTAINER_NAMES[@]}" + passthru mutagen project resume +} + +case "$COMMAND" in + start) + start + ;; + stop) + stop + ;; + pause) + pause + ;; + resume) + resume + ;; + *) + echo "Command not supported" + exit 1 + ;; +esac diff --git a/helm/app/Chart.yaml.twig b/helm/app/Chart.yaml.twig new file mode 100644 index 00000000..ee356e32 --- /dev/null +++ b/helm/app/Chart.yaml.twig @@ -0,0 +1,5 @@ +name: {{ @('workspace.name') }} +description: Base helm chart for {{ @('workspace.name') }} +version: 0.0.1 +sources: +home: diff --git a/helm/app/_twig/templates/service/varnish/configmap.yaml.twig b/helm/app/_twig/templates/service/varnish/configmap.yaml.twig new file mode 100644 index 00000000..edda6b92 --- /dev/null +++ b/helm/app/_twig/templates/service/varnish/configmap.yaml.twig @@ -0,0 +1,17 @@ +{% set blocks = 'docker/image/varnish/root/etc/varnish/' %} +{% verbatim %} +{{ if .Values.service.varnish | default .Values.docker.services.varnish.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + labels: + app.service: {{ .Values.resourcePrefix }}varnish + name: {{ .Values.resourcePrefix }}varnish-configuration +data: + default.vcl: | +{% endverbatim %} +{%- set config = include(blocks ~ 'default.vcl.twig', {varnish: {target_service: "{{ .Values.resourcePrefix }}webapp"}}) %} +{{ indent(config, 4) }} +{%- verbatim %} +{{ end }} +{% endverbatim %} diff --git a/helm/app/_twig/values.yaml/resources.yml.twig b/helm/app/_twig/values.yaml/resources.yml.twig new file mode 100644 index 00000000..21e3391d --- /dev/null +++ b/helm/app/_twig/values.yaml/resources.yml.twig @@ -0,0 +1,3 @@ +{# this file is deprecated, and instead resources attribute is serialised into the values directly #} +{# in the case of services, resource attribute is further deprecated and available continuing forward in services.*.resources #} +{{ to_nice_yaml(@('resources'), 2, 2) | raw }} diff --git a/helm/app/templates/_base_helper.tpl b/helm/app/templates/_base_helper.tpl new file mode 100644 index 00000000..ff215452 --- /dev/null +++ b/helm/app/templates/_base_helper.tpl @@ -0,0 +1,47 @@ +{{- define "application.volumes.backend" }}{{ end }} +{{- define "application.volumeMounts.backend" }}{{ end }} + +{{- define "application.volumes.all" }}{{ end }} +{{- define "application.volumeMounts.all" }}{{ end }} + +{{- define "application.volumes.wwwDataPaths" }}{{ end }} + +{{- define "application.volumes.console" -}} +{{- if .Values.persistence.mountVolumesOnConsole -}} +{{- template "application.volumes.backend" . -}} +{{- template "application.volumes.all" . -}} +{{- end -}} +{{- end }} +{{- define "application.volumeMounts.console" -}} +{{- if .Values.persistence.mountVolumesOnConsole -}} +{{- template "application.volumeMounts.backend" . -}} +{{- template "application.volumeMounts.all" . -}} +{{- end -}} +{{- end }} + +{{- define "service.environment.secret" }} +{{ if and .service.environment_secrets (.service.enabled | default true) }} +{{ if .Values.feature.sealed_secrets }} +apiVersion: bitnami.com/v1alpha1 +kind: SealedSecret +{{ else }} +apiVersion: v1 +kind: Secret +{{ end }} +metadata: + name: {{ .Values.resourcePrefix }}{{ .service_name }} + annotations: + argocd.argoproj.io/sync-wave: "1" +{{ if .Values.feature.sealed_secrets }} +{{ if ne .Values.sealed_secrets.scope "strict" }} + sealedsecrets.bitnami.com/{{ .Values.sealed_secrets.scope }}: "true" +{{ end }} +spec: + encryptedData: +{{ index .service.environment_secrets | toYaml | nindent 4 -}} +{{ else }} +stringData: +{{ index .service.environment_secrets | toYaml | nindent 2 -}} +{{ end }} +{{ end }} +{{- end }} diff --git a/helm/app/templates/application/app-init.yaml b/helm/app/templates/application/app-init.yaml new file mode 100644 index 00000000..29fbeacf --- /dev/null +++ b/helm/app/templates/application/app-init.yaml @@ -0,0 +1,64 @@ +{{- with mergeOverwrite (dict) (index .Values.docker.services "php-base") (index .Values.docker.services "console") (dict "environment" .Values.environment) -}} +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ $.Values.resourcePrefix }}app-init + annotations: + helm.sh/hook: "post-install" + helm.sh/hook-delete-policy: "before-hook-creation" + argocd.argoproj.io/hook: "Sync" + argocd.argoproj.io/hook-delete-policy: "BeforeHookCreation" + argocd.argoproj.io/sync-wave: "5" +spec: + backoffLimit: 0 + template: + spec: + restartPolicy: Never + containers: + - env: + {{- range $key, $value := .environment }} + {{- $tp := typeOf $value }} + - name: {{ $key | quote }} + {{- if eq $tp "string" }} + value: {{ tpl $value $ | quote }} + {{- else }} + value: {{ $value | quote }} + {{- end }} + {{- end }} + {{- if .environment_secrets }} + envFrom: + - secretRef: + name: {{ $.Values.resourcePrefix }}console + {{- end }} + image: {{ $.Values.docker.image.console | default .image | quote }} + imagePullPolicy: Always + name: app-init +{{ if eq $.Values.ingress.type "istio" }} + command: ["/bin/sh"] + args: ["-c", "/entrypoint.sh app init ; code=$? ; curl -vv -XPOST http://127.0.0.1:15020/quitquitquit ; exit $code"] +{{ else }} + command: ["/entrypoint.sh"] + args: ["app", "init"] +{{ end }} + resources: + limits: + memory: {{ $.Values.resources.memory.app_init }} + requests: + memory: {{ $.Values.resources.memory.app_init }} + volumeMounts: + {{- if not (eq "" (include "application.volumeMounts.console" $)) }} + {{- include "application.volumeMounts.console" $ | indent 8 }} + {{- else }} [] + {{- end }} +{{- if $.Values.docker.image_pull_config }} + imagePullSecrets: + - name: {{ $.Values.resourcePrefix }}image-pull-config +{{- end }} + restartPolicy: Never + enableServiceLinks: false + volumes: + {{- if not (eq "" (include "application.volumes.console" $)) }} + {{- include "application.volumes.console" $ | indent 6 }} + {{- else }} [] + {{- end }} +{{- end }} diff --git a/helm/app/templates/application/app-migrate.yaml b/helm/app/templates/application/app-migrate.yaml new file mode 100644 index 00000000..dc404df0 --- /dev/null +++ b/helm/app/templates/application/app-migrate.yaml @@ -0,0 +1,62 @@ +{{- with mergeOverwrite (dict) (index .Values.docker.services "php-base") (index .Values.docker.services "console") (dict "environment" .Values.environment) -}} +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ $.Values.resourcePrefix }}app-migrate + annotations: + helm.sh/hook: "pre-upgrade" + helm.sh/hook-delete-policy: "before-hook-creation" + argocd.argoproj.io/hook: "Sync" + argocd.argoproj.io/hook-delete-policy: "BeforeHookCreation" + argocd.argoproj.io/sync-wave: "10" +spec: + template: + spec: + containers: + - env: + {{- range $key, $value := .environment }} + {{- $tp := typeOf $value }} + - name: {{ $key | quote }} + {{- if eq $tp "string" }} + value: {{ tpl $value $ | quote }} + {{- else }} + value: {{ $value | quote }} + {{- end }} + {{- end }} + {{- if .environment_secrets }} + envFrom: + - secretRef: + name: {{ $.Values.resourcePrefix }}console + {{- end }} + image: {{ $.Values.docker.image.console | default .image }} + imagePullPolicy: Always + name: app-migrate +{{ if eq $.Values.ingress.type "istio" }} + command: ["/bin/sh"] + args: ["-c", "/entrypoint.sh app migrate ; code=$? ; curl -vv -XPOST http://127.0.0.1:15020/quitquitquit ; exit $code"] +{{ else }} + command: ["/entrypoint.sh"] + args: ["app", "migrate"] +{{ end }} + resources: + limits: + memory: {{ $.Values.resources.memory.app_migrate }} + requests: + memory: {{ $.Values.resources.memory.app_migrate }} + volumeMounts: + {{- if not (eq "" (include "application.volumeMounts.console" $)) }} + {{- include "application.volumeMounts.console" $ | indent 8 }} + {{- else }} [] + {{- end }} +{{- if $.Values.docker.image_pull_config }} + imagePullSecrets: + - name: {{ $.Values.resourcePrefix }}image-pull-config +{{- end }} + restartPolicy: Never + enableServiceLinks: false + volumes: + {{- if not (eq "" (include "application.volumes.console" $)) }} + {{- include "application.volumes.console" $ | indent 6 }} + {{- else }} [] + {{- end }} +{{- end }} diff --git a/helm/app/templates/application/console/deployment.yaml b/helm/app/templates/application/console/deployment.yaml new file mode 100644 index 00000000..2c34e23f --- /dev/null +++ b/helm/app/templates/application/console/deployment.yaml @@ -0,0 +1,71 @@ +{{- with mergeOverwrite (dict) (index .Values.docker.services "php-base") (index .Values.docker.services "console") (dict "environment" .Values.environment) -}} +{{- if .enabled -}} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ $.Values.resourcePrefix }}console + labels: + app.service: {{ $.Values.resourcePrefix }}console + annotations: + argocd.argoproj.io/sync-wave: "15" +spec: + replicas: 1 + revisionHistoryLimit: 2 + selector: + matchLabels: + app.service: {{ $.Values.resourcePrefix }}console + template: + metadata: + labels: + app.service: {{ $.Values.resourcePrefix }}console + spec: + containers: + - env: + {{- range $key, $value := .environment }} + {{- $tp := typeOf $value }} + - name: {{ $key | quote }} + {{- if eq $tp "string" }} + value: {{ tpl $value $ | quote }} + {{- else}} + value: {{ $value | quote }} + {{- end }} + {{- end }} + {{- if .environment_secrets }} + envFrom: + - secretRef: + name: {{ $.Values.resourcePrefix }}console + {{- end }} + image: {{ $.Values.docker.image.console | default .image }} + imagePullPolicy: Always + name: console + resources: + limits: + memory: {{ $.Values.resources.memory.console | default .resources.memory }} + requests: + memory: {{ $.Values.resources.memory.console | default .resources.memory }} + readinessProbe: + exec: + command: + - app + - state + initialDelaySeconds: 20 + periodSeconds: 10 + volumeMounts: + {{- if not (eq "" (include "application.volumeMounts.console" $)) }} + {{- include "application.volumeMounts.console" $ | indent 8 }} + {{- else }} [] + {{- end }} +{{- if $.Values.docker.image_pull_config }} + imagePullSecrets: + - name: {{ $.Values.resourcePrefix }}image-pull-config +{{- end }} + restartPolicy: Always + enableServiceLinks: false + volumes: + {{- if not (eq "" (include "application.volumes.console" $)) }} + {{- include "application.volumes.console" $ | indent 6 }} + {{- else }} [] + {{- end }} +status: {} +{{- end }} +{{- end }} diff --git a/helm/app/templates/application/console/secret.yaml b/helm/app/templates/application/console/secret.yaml new file mode 100644 index 00000000..db1aea56 --- /dev/null +++ b/helm/app/templates/application/console/secret.yaml @@ -0,0 +1,2 @@ +{{- $service := mergeOverwrite (dict) (index .Values.docker.services "php-base") (index .Values.docker.services "console") -}} +{{ template "service.environment.secret" (dict "service_name" "console" "service" $service "Values" .Values) }} diff --git a/helm/app/templates/application/cron/deployment.yaml b/helm/app/templates/application/cron/deployment.yaml new file mode 100644 index 00000000..c94f6a9b --- /dev/null +++ b/helm/app/templates/application/cron/deployment.yaml @@ -0,0 +1,82 @@ +{{- with mergeOverwrite (dict) (index .Values.docker.services "php-base") (index .Values.docker.services "cron") (dict "environment" .Values.environment) -}} +{{- if $.Values.service.cron | default .enabled -}} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ $.Values.resourcePrefix }}cron + labels: + app.service: {{ $.Values.resourcePrefix }}cron + annotations: + argocd.argoproj.io/sync-wave: "15" +spec: + replicas: 1 + revisionHistoryLimit: 2 + selector: + matchLabels: + app.service: {{ $.Values.resourcePrefix }}cron + template: + metadata: + labels: + app.service: {{ $.Values.resourcePrefix }}cron + spec: + {{- if not (eq "" (include "application.volumes.wwwDataPaths" $)) }} + initContainers: + - name: cron-volume-permissions + image: busybox + command: + - "/bin/chown" + - "-R" + - "www-data" + {{- include "application.volumes.wwwDataPaths" $ | indent 8 }} + volumeMounts: + {{- if not (and (eq "" (include "application.volumeMounts.backend" $)) (eq "" (include "application.volumeMounts.all" $)) ) }} + {{- include "application.volumeMounts.backend" $ | indent 8 }} + {{- include "application.volumeMounts.all" $ | indent 8 }} + {{- else }} [] + {{- end }} + {{- end }} + containers: + - name: cron + env: + {{- range $key, $value := .environment }} + {{- $tp := typeOf $value }} + - name: {{ $key | quote }} + {{- if eq $tp "string" }} + value: {{ tpl $value $ | quote }} + {{- else}} + value: {{ $value | quote }} + {{- end }} + {{- end }} + {{- if .environment_secrets }} + envFrom: + - secretRef: + name: {{ $.Values.resourcePrefix }}cron + {{- end }} + image: {{ $.Values.docker.image.cron | default .image }} + imagePullPolicy: Always + resources: + limits: + memory: {{ $.Values.resources.memory.cron | default .resources.memory }} + requests: + memory: {{ $.Values.resources.memory.cron | default .resources.memory }} + volumeMounts: + {{- if not (and (eq "" (include "application.volumeMounts.backend" $)) (eq "" (include "application.volumeMounts.all" $)) ) }} + {{- include "application.volumeMounts.backend" $ | indent 8 }} + {{- include "application.volumeMounts.all" $ | indent 8 }} + {{- else }} [] + {{- end }} +{{- if $.Values.docker.image_pull_config }} + imagePullSecrets: + - name: {{ $.Values.resourcePrefix }}image-pull-config +{{- end }} + restartPolicy: Always + enableServiceLinks: false + volumes: + {{- if not (and (eq "" (include "application.volumes.backend" $)) (eq "" (include "application.volumes.all" $)) ) }} + {{- include "application.volumes.backend" $ | indent 6 }} + {{- include "application.volumes.all" $ | indent 6 }} + {{- else }} [] + {{- end }} +status: {} +{{- end }} +{{- end }} diff --git a/helm/app/templates/application/cron/secret.yaml b/helm/app/templates/application/cron/secret.yaml new file mode 100644 index 00000000..84b39ae7 --- /dev/null +++ b/helm/app/templates/application/cron/secret.yaml @@ -0,0 +1,2 @@ +{{- $service := mergeOverwrite (dict) (index .Values.docker.services "php-base") (index .Values.docker.services "cron") -}} +{{ template "service.environment.secret" (dict "service_name" "cron" "service" $service "Values" .Values) }} diff --git a/helm/app/templates/application/image-pull-config.yaml b/helm/app/templates/application/image-pull-config.yaml new file mode 100644 index 00000000..f698a31c --- /dev/null +++ b/helm/app/templates/application/image-pull-config.yaml @@ -0,0 +1,25 @@ +{{ if .Values.docker.image_pull_config }} +{{ if .Values.feature.sealed_secrets }} +apiVersion: bitnami.com/v1alpha1 +kind: SealedSecret +{{ else }} +apiVersion: v1 +kind: Secret +{{ end }} +metadata: + name: {{ .Values.resourcePrefix }}image-pull-config + annotations: + argocd.argoproj.io/sync-wave: "1" +{{ if .Values.feature.sealed_secrets }} + sealedsecrets.bitnami.com/cluster-wide: "true" +spec: + template: + type: kubernetes.io/dockerconfigjson + encryptedData: + .dockerconfigjson: {{ .Values.docker.image_pull_config }} +{{ else }} +type: kubernetes.io/dockerconfigjson +data: + .dockerconfigjson: {{ .Values.docker.image_pull_config }} +{{ end }} +{{ end }} diff --git a/helm/app/templates/application/webapp/deployment.yaml b/helm/app/templates/application/webapp/deployment.yaml new file mode 100644 index 00000000..20c1840c --- /dev/null +++ b/helm/app/templates/application/webapp/deployment.yaml @@ -0,0 +1,160 @@ +{{- $service_php_fpm := mergeOverwrite (dict) (index .Values.docker.services "php-base") (index .Values.docker.services "php-fpm") (dict "environment" .Values.environment) -}} +{{- if .Values.docker.services.webapp.enabled -}} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Values.resourcePrefix }}webapp + labels: + app.service: {{ .Values.resourcePrefix }}webapp + annotations: + argocd.argoproj.io/sync-wave: "15" +spec: + replicas: 1 + revisionHistoryLimit: 2 + selector: + matchLabels: + app.service: {{ .Values.resourcePrefix }}webapp + template: + metadata: + labels: + app.service: {{ .Values.resourcePrefix }}webapp + spec: + {{- if and $service_php_fpm.enabled (not (eq "" (include "application.volumes.wwwDataPaths" .))) }} + initContainers: + - name: webapp-volume-permissions + image: busybox + command: + - "/bin/chown" + - "-R" + - "www-data" + {{- include "application.volumes.wwwDataPaths" . | indent 8 }} + volumeMounts: + {{- if not (and (eq "" (include "application.volumeMounts.backend" .)) (eq "" (include "application.volumeMounts.all" .)) ) }} + {{- include "application.volumeMounts.backend" . | indent 8 }} + {{- include "application.volumeMounts.all" . | indent 8 }} + {{- else }} [] + {{- end }} + {{- end }} + containers: + {{- with .Values.docker.services.nginx }} + - name: nginx + env: + {{- range $key, $value := .environment }} + {{- $tp := typeOf $value }} + - name: {{ $key | quote }} + {{- if eq $tp "string" }} + value: {{ tpl $value $ | quote }} + {{- else}} + value: {{ $value | quote }} + {{- end }} + {{- end }} + {{- if .environment_secrets }} + envFrom: + - secretRef: + name: {{ $.Values.resourcePrefix }}nginx + {{- end }} + image: {{ $.Values.docker.image.nginx | default .image }} + imagePullPolicy: Always + ports: + - name: http + containerPort: 80 + resources: + limits: + memory: {{ $.Values.resources.memory.nginx | default .resources.memory }} + requests: + memory: {{ $.Values.resources.memory.nginx | default .resources.memory }} + readinessProbe: + tcpSocket: + port: 80 + initialDelaySeconds: 5 + periodSeconds: 10 + volumeMounts: + {{- if not (eq "" (include "application.volumeMounts.all" $)) }} + {{- include "application.volumeMounts.all" $ | indent 8 }} + {{- else }} [] + {{- end }} + {{- end }} + + {{- with $service_php_fpm }} + - name: php-fpm + env: + {{- range $key, $value := .environment }} + {{- $tp := typeOf $value }} + - name: {{ $key | quote }} + {{- if eq $tp "string" }} + value: {{ tpl $value $ | quote }} + {{- else}} + value: {{ $value | quote }} + {{- end }} + {{- end }} + {{- if .environment_secrets }} + envFrom: + - secretRef: + name: {{ $.Values.resourcePrefix }}php-fpm + {{- end }} + image: {{ $.Values.docker.image.fpm | default .image | quote }} + imagePullPolicy: Always + ports: + - containerPort: 9000 + resources: + limits: + memory: {{ $.Values.resources.memory.php_fpm | default .resources.memory }} + requests: + memory: {{ $.Values.resources.memory.php_fpm | default .resources.memory }} + readinessProbe: + tcpSocket: + port: 9000 + initialDelaySeconds: 5 + periodSeconds: 10 + volumeMounts: + {{- if not (and (eq "" (include "application.volumeMounts.backend" $)) (eq "" (include "application.volumeMounts.all" $)) ) }} + {{- include "application.volumeMounts.backend" $ | indent 8 }} + {{- include "application.volumeMounts.all" $ | indent 8 }} + {{- else }} [] + {{- end }} + {{- end }} + + {{- with index .Values.docker.services "php-fpm-exporter" }} + {{- if $.Values.service.php_fpm_exporter | default .enabled }} + - name: php-fpm-exporter + env: + {{- range $key, $value := .environment }} + {{- $tp := typeOf $value }} + - name: {{ $key | quote }} + {{- if eq $tp "string" }} + value: {{ tpl $value $ | quote }} + {{- else}} + value: {{ $value | quote }} + {{- end }} + {{- end }} + image: {{ .image | quote }} + imagePullPolicy: Always + ports: + - name: php-fpm-metrics + containerPort: 9253 + resources: + limits: + memory: {{ $.Values.resources.memory.php_fpm_exporter | default .resources.memory }} + requests: + memory: {{ $.Values.resources.memory.php_fpm_exporter | default .resources.memory }} + readinessProbe: + tcpSocket: + port: 9253 + initialDelaySeconds: 5 + periodSeconds: 10 + {{- end }} + {{- end }} +{{- if .Values.docker.image_pull_config }} + imagePullSecrets: + - name: {{ .Values.resourcePrefix }}image-pull-config +{{- end }} + restartPolicy: Always + enableServiceLinks: false + volumes: + {{- if not (and (eq "" (include "application.volumes.backend" .)) (eq "" (include "application.volumes.all" .)) ) }} + {{- include "application.volumes.backend" . | indent 6 }} + {{- include "application.volumes.all" . | indent 6 }} + {{- else }} [] + {{- end }} +status: {} +{{- end }} diff --git a/helm/app/templates/application/webapp/podmonitor.yaml b/helm/app/templates/application/webapp/podmonitor.yaml new file mode 100644 index 00000000..afff13a3 --- /dev/null +++ b/helm/app/templates/application/webapp/podmonitor.yaml @@ -0,0 +1,19 @@ +{{- if and .Values.docker.services.webapp.enabled .Values.prometheus.podMonitoring -}} +apiVersion: monitoring.coreos.com/v1 +kind: PodMonitor +metadata: + name: {{ .Values.resourcePrefix }}webapp + labels: + app.service: {{ .Values.resourcePrefix }}webapp +spec: + selector: + matchLabels: + app.service: {{ .Values.resourcePrefix }}webapp + podMetricsEndpoints: +{{- if .Values.docker.services.nginx.metricsEnabled -}} +{{ .Values.docker.services.nginx.metricsEndpoints | toYaml | nindent 6 -}} +{{- end -}} +{{- if and (.Values.service.php_fpm_exporter | default (index .Values.docker.services "php-fpm-exporter" "enabled")) (index .Values.docker.services "php-fpm-exporter" "metricsEnabled") -}} +{{ index .Values.docker.services "php-fpm-exporter" "metricsEndpoints" | toYaml | nindent 6 -}} +{{- end -}} +{{- end -}} diff --git a/helm/app/templates/application/webapp/secret-nginx.yaml b/helm/app/templates/application/webapp/secret-nginx.yaml new file mode 100644 index 00000000..d084b784 --- /dev/null +++ b/helm/app/templates/application/webapp/secret-nginx.yaml @@ -0,0 +1 @@ +{{ template "service.environment.secret" (dict "service_name" "nginx" "service" .Values.docker.services.nginx "Values" .Values) }} diff --git a/helm/app/templates/application/webapp/secret-php-fpm.yaml b/helm/app/templates/application/webapp/secret-php-fpm.yaml new file mode 100644 index 00000000..6d8df564 --- /dev/null +++ b/helm/app/templates/application/webapp/secret-php-fpm.yaml @@ -0,0 +1,2 @@ +{{- $service := mergeOverwrite (dict) (index .Values.docker.services "php-base") (index .Values.docker.services "php-fpm") -}} +{{ template "service.environment.secret" (dict "service_name" "php-fpm" "service" $service "Values" .Values) }} diff --git a/helm/app/templates/application/webapp/service.yaml b/helm/app/templates/application/webapp/service.yaml new file mode 100644 index 00000000..fd58270d --- /dev/null +++ b/helm/app/templates/application/webapp/service.yaml @@ -0,0 +1,17 @@ +{{- if index .Values.docker.services .Values.ingress.target_service "enabled" -}} +apiVersion: v1 +kind: Service +metadata: + labels: + app.service: {{ .Values.resourcePrefix }}webapp + name: {{ .Values.resourcePrefix }}webapp +spec: + ports: + - name: http-80 + port: 80 + targetPort: 80 + selector: + app.service: {{ .Values.resourcePrefix }}webapp +status: + loadBalancer: {} +{{- end }} diff --git a/helm/app/templates/service/elasticsearch/deployment.yaml b/helm/app/templates/service/elasticsearch/deployment.yaml new file mode 100644 index 00000000..375c45be --- /dev/null +++ b/helm/app/templates/service/elasticsearch/deployment.yaml @@ -0,0 +1,62 @@ +{{- with .Values.docker.services.elasticsearch -}} +{{- if $.Values.service.elasticsearch | default .enabled -}} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ $.Values.resourcePrefix }}elasticsearch + annotations: + argocd.argoproj.io/sync-wave: "4" + labels: + app.service: {{ $.Values.resourcePrefix }}elasticsearch +spec: + replicas: 1 + selector: + matchLabels: + app.service: {{ $.Values.resourcePrefix }}elasticsearch +{{- if $.Values.persistence.elasticsearch.enabled }} + strategy: + type: Recreate +{{- end }} + template: + metadata: + labels: + app.service: {{ $.Values.resourcePrefix }}elasticsearch + spec: + securityContext: + fsGroup: 1000 + containers: + - env: + - name: ES_JAVA_OPTS + value: -Xmx512m -Xms512m + - name: discovery.type + value: single-node + image: {{ $.Values.docker.image.elasticsearch | default .image | quote }} + imagePullPolicy: Always + name: elasticsearch + ports: + - containerPort: 9200 + resources: + limits: + memory: {{ $.Values.resources.memory.elasticsearch | default .resources.memory }} + requests: + memory: {{ $.Values.resources.memory.elasticsearch | default .resources.memory }} + readinessProbe: + tcpSocket: + port: 9200 + initialDelaySeconds: 5 + periodSeconds: 10 + volumeMounts: + - name: {{ $.Values.resourcePrefix }}elasticsearch-persistent-storage + mountPath: /usr/share/elasticsearch/data + restartPolicy: Always + volumes: + - name: {{ $.Values.resourcePrefix }}elasticsearch-persistent-storage +{{- if $.Values.persistence.elasticsearch.enabled }} + persistentVolumeClaim: + claimName: {{ $.Values.resourcePrefix }}elasticsearch-pv-claim +{{- else }} + emptyDir: {} +{{- end }} +status: {} +{{- end }} +{{- end }} diff --git a/helm/app/templates/service/elasticsearch/pvc.yaml b/helm/app/templates/service/elasticsearch/pvc.yaml new file mode 100644 index 00000000..9132c047 --- /dev/null +++ b/helm/app/templates/service/elasticsearch/pvc.yaml @@ -0,0 +1,31 @@ +{{ if and .Values.persistence.elasticsearch.enabled (.Values.service.elasticsearch | default .Values.docker.services.elasticsearch.enabled) -}} + +{{- with .Values.persistence.elasticsearch -}} + +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: {{ $.Values.resourcePrefix }}elasticsearch-pv-claim + labels: + app.service: {{ $.Values.resourcePrefix }}elasticsearch +spec: + accessModes: + - {{ .accessMode | quote }} + resources: + requests: + storage: {{ .size | quote }} +{{- if .storageClass }} +{{- if (eq "-" .storageClass) }} + storageClassName: "" +{{- else }} + storageClassName: {{ .storageClass | quote }} +{{- end }} +{{- end }} +{{- if .selector }} + selector: + {{- .selector | toYaml | nindent 4 }} +{{- end }} + +{{- end }} + +{{- end }} diff --git a/helm/app/templates/service/elasticsearch/service.yaml b/helm/app/templates/service/elasticsearch/service.yaml new file mode 100644 index 00000000..cdaabf97 --- /dev/null +++ b/helm/app/templates/service/elasticsearch/service.yaml @@ -0,0 +1,17 @@ +{{ if .Values.service.elasticsearch | default .Values.docker.services.elasticsearch.enabled }} +apiVersion: v1 +kind: Service +metadata: + labels: + app.service: {{ .Values.resourcePrefix }}elasticsearch + name: {{ .Values.resourcePrefix }}elasticsearch +spec: + ports: + - name: "9200" + port: 9200 + targetPort: 9200 + selector: + app.service: {{ .Values.resourcePrefix }}elasticsearch +status: + loadBalancer: {} +{{ end }} diff --git a/helm/app/templates/service/mysql/deployment.yaml b/helm/app/templates/service/mysql/deployment.yaml new file mode 100644 index 00000000..40a283fe --- /dev/null +++ b/helm/app/templates/service/mysql/deployment.yaml @@ -0,0 +1,73 @@ +{{- with .Values.docker.services.mysql -}} +{{- if $.Values.service.mysql | default .enabled -}} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ $.Values.resourcePrefix }}mysql + annotations: + argocd.argoproj.io/sync-wave: "4" + labels: + app.service: {{ $.Values.resourcePrefix }}mysql +spec: + replicas: 1 + selector: + matchLabels: + app.service: {{ $.Values.resourcePrefix }}mysql +{{- if $.Values.persistence.mysql.enabled }} + strategy: + type: Recreate +{{- end }} + template: + metadata: + labels: + app.service: {{ $.Values.resourcePrefix }}mysql + spec: + containers: + - env: + {{- range $key, $value := .environment }} + - name: {{ $key | quote }} + value: {{ $value | quote }} + {{- end }} + {{- if .environment_secrets }} + envFrom: + - secretRef: + name: {{ $.Values.resourcePrefix }}mysql + {{- end }} + image: {{ $.Values.docker.image.mysql | default .image | quote }} + imagePullPolicy: Always + name: mysql + {{- if .options }} + args: + {{- range $var, $value := .options }} + {{- if $value }} + - {{ print "--" $var "=" $value | quote }} + {{- end }} + {{- end }} + {{- end }} + ports: + - containerPort: 3306 + resources: + limits: + memory: {{ $.Values.resources.memory.mysql | default .resources.memory }} + requests: + memory: {{ $.Values.resources.memory.mysql | default .resources.memory }} + readinessProbe: + tcpSocket: + port: 3306 + initialDelaySeconds: 5 + periodSeconds: 10 + volumeMounts: + - name: {{ $.Values.resourcePrefix }}mysql-persistent-storage + mountPath: /var/lib/mysql + restartPolicy: Always + volumes: + - name: {{ $.Values.resourcePrefix }}mysql-persistent-storage +{{- if $.Values.persistence.mysql.enabled }} + persistentVolumeClaim: + claimName: {{ $.Values.resourcePrefix }}mysql-pv-claim +{{- else }} + emptyDir: {} +{{- end }} +status: {} +{{- end }} +{{- end }} diff --git a/helm/app/templates/service/mysql/pvc.yaml b/helm/app/templates/service/mysql/pvc.yaml new file mode 100644 index 00000000..33f48922 --- /dev/null +++ b/helm/app/templates/service/mysql/pvc.yaml @@ -0,0 +1,31 @@ +{{ if and .Values.persistence.mysql.enabled (.Values.service.mysql | default .Values.docker.services.mysql.enabled) -}} + +{{- with .Values.persistence.mysql -}} + +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: {{ $.Values.resourcePrefix }}mysql-pv-claim + labels: + app.service: {{ $.Values.resourcePrefix }}mysql +spec: + accessModes: + - {{ .accessMode | quote }} + resources: + requests: + storage: {{ .size | quote }} +{{- if .storageClass }} +{{- if (eq "-" .storageClass) }} + storageClassName: "" +{{- else }} + storageClassName: {{ .storageClass | quote }} +{{- end }} +{{- end }} +{{- if .selector }} + selector: + {{- .selector | toYaml | nindent 4 }} +{{- end }} + +{{- end }} + +{{- end }} diff --git a/helm/app/templates/service/mysql/secret.yaml b/helm/app/templates/service/mysql/secret.yaml new file mode 100644 index 00000000..88b0d814 --- /dev/null +++ b/helm/app/templates/service/mysql/secret.yaml @@ -0,0 +1 @@ +{{ template "service.environment.secret" (dict "service_name" "mysql" "service" .Values.docker.services.mysql "Values" .Values) }} diff --git a/helm/app/templates/service/mysql/service.yaml b/helm/app/templates/service/mysql/service.yaml new file mode 100644 index 00000000..748b9577 --- /dev/null +++ b/helm/app/templates/service/mysql/service.yaml @@ -0,0 +1,17 @@ +{{ if .Values.service.mysql | default .Values.docker.services.mysql.enabled }} +apiVersion: v1 +kind: Service +metadata: + labels: + app.service: {{ .Values.resourcePrefix }}mysql + name: {{ .Values.resourcePrefix }}mysql +spec: + ports: + - name: "3306" + port: 3306 + targetPort: 3306 + selector: + app.service: {{ .Values.resourcePrefix }}mysql +status: + loadBalancer: {} +{{ end }} diff --git a/helm/app/templates/service/postgres/deployment.yaml b/helm/app/templates/service/postgres/deployment.yaml new file mode 100644 index 00000000..f6fbf946 --- /dev/null +++ b/helm/app/templates/service/postgres/deployment.yaml @@ -0,0 +1,65 @@ +{{- with .Values.docker.services.postgres -}} +{{- if $.Values.service.postgres | default .enabled -}} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ $.Values.resourcePrefix }}postgres + annotations: + argocd.argoproj.io/sync-wave: "4" + labels: + app.service: {{ $.Values.resourcePrefix }}postgres +spec: + replicas: 1 + selector: + matchLabels: + app.service: {{ $.Values.resourcePrefix }}postgres +{{- if $.Values.persistence.postgres.enabled }} + strategy: + type: Recreate +{{- end }} + template: + metadata: + labels: + app.service: {{ $.Values.resourcePrefix }}postgres + spec: + containers: + - env: + {{- range $key, $value := .environment }} + - name: {{ $key | quote }} + value: {{ $value | quote }} + {{- end }} + {{- if .environment_secrets }} + envFrom: + - secretRef: + name: {{ $.Values.resourcePrefix }}postgres + {{- end }} + image: {{ .image | quote }} + imagePullPolicy: Always + name: postgres + ports: + - containerPort: 5432 + resources: + limits: + memory: {{ $.Values.resources.memory.postgres | default .resources.memory }} + requests: + memory: {{ $.Values.resources.memory.postgres | default .resources.memory }} + readinessProbe: + tcpSocket: + port: 5432 + initialDelaySeconds: 5 + periodSeconds: 10 + volumeMounts: + - name: {{ $.Values.resourcePrefix }}postgres-persistent-storage + mountPath: /var/lib/postgresql/data + restartPolicy: Always + volumes: + - name: {{ $.Values.resourcePrefix }}postgres-persistent-storage +{{- if $.Values.persistence.postgres.enabled }} + persistentVolumeClaim: + claimName: {{ $.Values.resourcePrefix }}postgres-pv-claim +{{- else }} + emptyDir: {} +{{- end }} +status: {} +{{- end }} +{{- end }} diff --git a/helm/app/templates/service/postgres/pvc.yaml b/helm/app/templates/service/postgres/pvc.yaml new file mode 100644 index 00000000..24366814 --- /dev/null +++ b/helm/app/templates/service/postgres/pvc.yaml @@ -0,0 +1,31 @@ +{{ if and .Values.persistence.postgres.enabled (.Values.service.postgres | default .Values.docker.services.postgres.enabled) -}} + +{{- with .Values.persistence.postgres -}} + +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: {{ $.Values.resourcePrefix }}postgres-pv-claim + labels: + app.service: {{ $.Values.resourcePrefix }}postgres +spec: + accessModes: + - {{ .accessMode | quote }} + resources: + requests: + storage: {{ .size | quote }} +{{- if .storageClass }} +{{- if (eq "-" .storageClass) }} + storageClassName: "" +{{- else }} + storageClassName: {{ .storageClass | quote }} +{{- end }} +{{- end }} +{{- if .selector }} + selector: + {{- .selector | toYaml | nindent 4 }} +{{- end }} + +{{- end }} + +{{- end }} diff --git a/helm/app/templates/service/postgres/secret.yaml b/helm/app/templates/service/postgres/secret.yaml new file mode 100644 index 00000000..58ffaf90 --- /dev/null +++ b/helm/app/templates/service/postgres/secret.yaml @@ -0,0 +1 @@ +{{ template "service.environment.secret" (dict "service_name" "postgres" "service" .Values.docker.services.postgres "Values" .Values) }} diff --git a/helm/app/templates/service/postgres/service.yaml b/helm/app/templates/service/postgres/service.yaml new file mode 100644 index 00000000..d5353aac --- /dev/null +++ b/helm/app/templates/service/postgres/service.yaml @@ -0,0 +1,17 @@ +{{ if .Values.service.postgres | default .Values.docker.services.postgres.enabled }} +apiVersion: v1 +kind: Service +metadata: + labels: + app.service: {{ .Values.resourcePrefix }}postgres + name: {{ .Values.resourcePrefix }}postgres +spec: + ports: + - name: "5432" + port: 5432 + targetPort: 5432 + selector: + app.service: {{ .Values.resourcePrefix }}postgres +status: + loadBalancer: {} +{{ end }} diff --git a/helm/app/templates/service/rabbitmq/deployment.yaml b/helm/app/templates/service/rabbitmq/deployment.yaml new file mode 100644 index 00000000..be11021b --- /dev/null +++ b/helm/app/templates/service/rabbitmq/deployment.yaml @@ -0,0 +1,66 @@ +{{- with .Values.docker.services.rabbitmq -}} +{{- if $.Values.service.rabbitmq | default .enabled -}} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ $.Values.resourcePrefix }}rabbitmq + annotations: + argocd.argoproj.io/sync-wave: "4" + labels: + app.service: {{ $.Values.resourcePrefix }}rabbitmq +spec: + replicas: 1 + selector: + matchLabels: + app.service: {{ $.Values.resourcePrefix }}rabbitmq +{{- if $.Values.persistence.rabbitmq.enabled }} + strategy: + type: Recreate +{{- end }} + template: + metadata: + labels: + app.service: {{ $.Values.resourcePrefix }}rabbitmq + spec: + containers: + - env: + {{- range $key, $value := .environment }} + - name: {{ $key | quote }} + value: {{ $value | quote }} + {{- end }} + {{- if .environment_secrets }} + envFrom: + - secretRef: + name: {{ $.Values.resourcePrefix }}rabbitmq + {{- end }} + image: {{ $.Values.docker.image.rabbitmq | default .image | quote }} + imagePullPolicy: Always + name: rabbitmq + ports: + - containerPort: 5672 + - containerPort: 15672 + resources: + limits: + memory: {{ $.Values.resources.memory.rabbitmq | default .resources.memory }} + requests: + memory: {{ $.Values.resources.memory.rabbitmq | default .resources.memory }} + readinessProbe: + tcpSocket: + port: 5672 + initialDelaySeconds: 5 + periodSeconds: 10 + volumeMounts: + - name: {{ $.Values.resourcePrefix }}rabbitmq-persistent-storage + mountPath: /var/lib/rabbitmq + restartPolicy: Always + volumes: + - name: {{ $.Values.resourcePrefix }}rabbitmq-persistent-storage +{{- if $.Values.persistence.rabbitmq.enabled }} + persistentVolumeClaim: + claimName: {{ $.Values.resourcePrefix }}rabbitmq-pv-claim +{{- else }} + emptyDir: {} +{{- end }} +status: {} +{{- end }} +{{- end }} diff --git a/helm/app/templates/service/rabbitmq/pvc.yaml b/helm/app/templates/service/rabbitmq/pvc.yaml new file mode 100644 index 00000000..8e119903 --- /dev/null +++ b/helm/app/templates/service/rabbitmq/pvc.yaml @@ -0,0 +1,31 @@ +{{ if and .Values.persistence.rabbitmq.enabled (.Values.service.rabbitmq | default .Values.docker.services.rabbitmq.enabled) -}} + +{{- with .Values.persistence.rabbitmq -}} + +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: {{ $.Values.resourcePrefix }}rabbitmq-pv-claim + labels: + app.service: {{ $.Values.resourcePrefix }}rabbitmq +spec: + accessModes: + - {{ .accessMode | quote }} + resources: + requests: + storage: {{ .size | quote }} +{{- if .storageClass }} +{{- if (eq "-" .storageClass) }} + storageClassName: "" +{{- else }} + storageClassName: {{ .storageClass | quote }} +{{- end }} +{{- end }} +{{- if .selector }} + selector: + {{- .selector | toYaml | nindent 4 }} +{{- end }} + +{{- end }} + +{{- end }} diff --git a/helm/app/templates/service/rabbitmq/secret.yaml b/helm/app/templates/service/rabbitmq/secret.yaml new file mode 100644 index 00000000..5104e43a --- /dev/null +++ b/helm/app/templates/service/rabbitmq/secret.yaml @@ -0,0 +1 @@ +{{ template "service.environment.secret" (dict "service_name" "rabbitmq" "service" .Values.docker.services.rabbitmq "Values" .Values) }} diff --git a/helm/app/templates/service/rabbitmq/service.yaml b/helm/app/templates/service/rabbitmq/service.yaml new file mode 100644 index 00000000..aaaaa634 --- /dev/null +++ b/helm/app/templates/service/rabbitmq/service.yaml @@ -0,0 +1,20 @@ +{{ if .Values.service.rabbitmq | default .Values.docker.services.rabbitmq.enabled }} +apiVersion: v1 +kind: Service +metadata: + labels: + app.service: {{ .Values.resourcePrefix }}rabbitmq + name: {{ .Values.resourcePrefix }}rabbitmq +spec: + ports: + - name: "5672" + port: 5672 + targetPort: 5672 + - name: "15672" + port: 15672 + targetPort: 15672 + selector: + app.service: {{ .Values.resourcePrefix }}rabbitmq +status: + loadBalancer: {} +{{ end }} diff --git a/helm/app/templates/service/redis-session/deployment.yaml b/helm/app/templates/service/redis-session/deployment.yaml new file mode 100644 index 00000000..58ecaaf8 --- /dev/null +++ b/helm/app/templates/service/redis-session/deployment.yaml @@ -0,0 +1,70 @@ +{{- with .Values.docker.services.redis_session -}} +{{- if $.Values.service.redis_session | default .enabled -}} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ $.Values.resourcePrefix }}redis-session + annotations: + argocd.argoproj.io/sync-wave: "4" + labels: + app.service: {{ $.Values.resourcePrefix }}redis-session +spec: + replicas: 1 + selector: + matchLabels: + app.service: {{ $.Values.resourcePrefix }}redis-session +{{- if $.Values.persistence.redis_session.enabled }} + strategy: + type: Recreate +{{- end }} + template: + metadata: + labels: + app.service: {{ $.Values.resourcePrefix }}redis-session + spec: + containers: + - args: + - redis-server + - --maxmemory + - "1073742000" + - --maxmemory-policy + - volatile-ttl + - --save + - "3600" + - "1" + - --save + - "300" + - "100" + - --save + - "60" + - "10000" + image: {{ .image | quote }} + imagePullPolicy: Always + name: redis-session + ports: + - containerPort: 6379 + resources: + limits: + memory: {{ $.Values.resources.memory.redis_session | default .resources.memory }} + requests: + memory: {{ $.Values.resources.memory.redis_session | default .resources.memory }} + readinessProbe: + tcpSocket: + port: 6379 + initialDelaySeconds: 5 + periodSeconds: 10 + volumeMounts: + - name: {{ $.Values.resourcePrefix }}redis-session-persistent-storage + mountPath: /data + restartPolicy: Always + volumes: + - name: {{ $.Values.resourcePrefix }}redis-session-persistent-storage +{{- if $.Values.persistence.redis_session.enabled }} + persistentVolumeClaim: + claimName: {{ $.Values.resourcePrefix }}redis-session-pv-claim +{{- else }} + emptyDir: {} +{{- end }} +status: {} +{{- end }} +{{- end }} diff --git a/helm/app/templates/service/redis-session/pvc.yaml b/helm/app/templates/service/redis-session/pvc.yaml new file mode 100644 index 00000000..875b59b1 --- /dev/null +++ b/helm/app/templates/service/redis-session/pvc.yaml @@ -0,0 +1,31 @@ +{{ if and .Values.persistence.redis_session.enabled (.Values.service.redis_session | default .Values.docker.services.redis_session.enabled) -}} + +{{- with .Values.persistence.redis_session -}} + +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: {{ $.Values.resourcePrefix }}redis-session-pv-claim + labels: + app.service: {{ $.Values.resourcePrefix }}redis-session +spec: + accessModes: + - {{ .accessMode | quote }} + resources: + requests: + storage: {{ .size | quote }} +{{- if .storageClass }} +{{- if (eq "-" .storageClass) }} + storageClassName: "" +{{- else }} + storageClassName: {{ .storageClass | quote }} +{{- end }} +{{- end }} +{{- if .selector }} + selector: + {{- .selector | toYaml | nindent 4 }} +{{- end }} + +{{- end }} + +{{- end }} diff --git a/helm/app/templates/service/redis-session/service.yaml b/helm/app/templates/service/redis-session/service.yaml new file mode 100644 index 00000000..db1eda54 --- /dev/null +++ b/helm/app/templates/service/redis-session/service.yaml @@ -0,0 +1,17 @@ +{{ if .Values.service.redis_session | default .Values.docker.services.redis_session.enabled }} +apiVersion: v1 +kind: Service +metadata: + labels: + app.service: {{ .Values.resourcePrefix }}redis-session + name: {{ .Values.resourcePrefix }}redis-session +spec: + ports: + - name: "6379" + port: 6379 + targetPort: 6379 + selector: + app.service: {{ .Values.resourcePrefix }}redis-session +status: + loadBalancer: {} +{{ end }} \ No newline at end of file diff --git a/helm/app/templates/service/redis/deployment.yaml b/helm/app/templates/service/redis/deployment.yaml new file mode 100644 index 00000000..bd998595 --- /dev/null +++ b/helm/app/templates/service/redis/deployment.yaml @@ -0,0 +1,71 @@ +{{- with .Values.docker.services.redis -}} +{{- if $.Values.service.redis | default .enabled -}} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ $.Values.resourcePrefix }}redis + annotations: + argocd.argoproj.io/sync-wave: "4" + labels: + app.service: {{ $.Values.resourcePrefix }}redis +spec: + replicas: 1 + selector: + matchLabels: + app.service: {{ $.Values.resourcePrefix }}redis +{{- if $.Values.persistence.redis.enabled }} + strategy: + type: Recreate +{{- end }} + template: + metadata: + creationTimestamp: null + labels: + app.service: {{ $.Values.resourcePrefix }}redis + spec: + containers: + - args: + - redis-server + - --maxmemory + - "1073742000" + - --maxmemory-policy + - allkeys-lru + - --save + - "3600" + - "1" + - --save + - "300" + - "100" + - --save + - "60" + - "10000" + image: {{ .image | quote }} + imagePullPolicy: Always + name: redis + ports: + - containerPort: 6379 + resources: + limits: + memory: {{ $.Values.resources.memory.redis | default .resources.memory }} + requests: + memory: {{ $.Values.resources.memory.redis | default .resources.memory }} + readinessProbe: + tcpSocket: + port: 6379 + initialDelaySeconds: 5 + periodSeconds: 10 + volumeMounts: + - name: {{ $.Values.resourcePrefix }}redis-persistent-storage + mountPath: /data + restartPolicy: Always + volumes: + - name: {{ $.Values.resourcePrefix }}redis-persistent-storage +{{- if $.Values.persistence.redis.enabled }} + persistentVolumeClaim: + claimName: {{ $.Values.resourcePrefix }}redis-pv-claim +{{- else }} + emptyDir: {} +{{- end }} +status: {} +{{- end }} +{{- end }} diff --git a/helm/app/templates/service/redis/pvc.yaml b/helm/app/templates/service/redis/pvc.yaml new file mode 100644 index 00000000..fc7ce86c --- /dev/null +++ b/helm/app/templates/service/redis/pvc.yaml @@ -0,0 +1,31 @@ +{{ if and .Values.persistence.redis.enabled (.Values.service.redis | default .Values.docker.services.redis.enabled) -}} + +{{- with .Values.persistence.redis -}} + +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: {{ $.Values.resourcePrefix }}redis-pv-claim + labels: + app.service: {{ $.Values.resourcePrefix }}redis +spec: + accessModes: + - {{ .accessMode | quote }} + resources: + requests: + storage: {{ .size | quote }} +{{- if .storageClass }} +{{- if (eq "-" .storageClass) }} + storageClassName: "" +{{- else }} + storageClassName: {{ .storageClass | quote }} +{{- end }} +{{- end }} +{{- if .selector }} + selector: + {{- .selector | toYaml | nindent 4 }} +{{- end }} + +{{- end }} + +{{- end }} diff --git a/helm/app/templates/service/redis/service.yaml b/helm/app/templates/service/redis/service.yaml new file mode 100644 index 00000000..198b9e70 --- /dev/null +++ b/helm/app/templates/service/redis/service.yaml @@ -0,0 +1,17 @@ +{{ if .Values.service.redis | default .Values.docker.services.redis.enabled }} +apiVersion: v1 +kind: Service +metadata: + labels: + app.service: {{ .Values.resourcePrefix }}redis + name: {{ .Values.resourcePrefix }}redis +spec: + ports: + - name: "6379" + port: 6379 + targetPort: 6379 + selector: + app.service: {{ .Values.resourcePrefix }}redis +status: + loadBalancer: {} +{{ end }} \ No newline at end of file diff --git a/helm/app/templates/service/tideways/deployment.yaml b/helm/app/templates/service/tideways/deployment.yaml new file mode 100644 index 00000000..a2f62dcd --- /dev/null +++ b/helm/app/templates/service/tideways/deployment.yaml @@ -0,0 +1,41 @@ +{{- with .Values.docker.services.tideways -}} +{{- if $.Values.service.tideways | default .enabled -}} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ $.Values.resourcePrefix }}tideways + annotations: + argocd.argoproj.io/sync-wave: "4" + labels: + app.service: {{ $.Values.resourcePrefix }}tideways +spec: + replicas: 1 + selector: + matchLabels: + app.service: {{ $.Values.resourcePrefix }}tideways + template: + metadata: + creationTimestamp: null + labels: + app.service: {{ $.Values.resourcePrefix }}tideways + spec: + containers: + - image: {{ .image | quote }} + imagePullPolicy: Always + name: tideways + ports: + - containerPort: 9135 + resources: + limits: + memory: {{ $.Values.resources.memory.tideways | default .resources.memory }} + requests: + memory: {{ $.Values.resources.memory.tideways | default .resources.memory }} + readinessProbe: + tcpSocket: + port: 9135 + initialDelaySeconds: 5 + periodSeconds: 10 + restartPolicy: Always +status: {} +{{- end }} +{{- end }} diff --git a/helm/app/templates/service/tideways/service.yaml b/helm/app/templates/service/tideways/service.yaml new file mode 100644 index 00000000..0be11631 --- /dev/null +++ b/helm/app/templates/service/tideways/service.yaml @@ -0,0 +1,17 @@ +{{ if .Values.service.tideways | default .Values.docker.services.tideways.enabled }} +apiVersion: v1 +kind: Service +metadata: + labels: + app.service: {{ .Values.resourcePrefix }}tideways + name: {{ .Values.resourcePrefix }}tideways +spec: + ports: + - name: "9135" + port: 9135 + targetPort: 9135 + selector: + app.service: {{ .Values.resourcePrefix }}tideways +status: + loadBalancer: {} +{{ end }} diff --git a/helm/app/templates/service/varnish/headless-service.yaml b/helm/app/templates/service/varnish/headless-service.yaml new file mode 100644 index 00000000..06e01dd5 --- /dev/null +++ b/helm/app/templates/service/varnish/headless-service.yaml @@ -0,0 +1,18 @@ +{{ if .Values.service.varnish | default .Values.docker.services.varnish.enabled }} +apiVersion: v1 +kind: Service +metadata: + labels: + app.service: {{ .Values.resourcePrefix }}varnish + name: {{ .Values.resourcePrefix }}varnish-headless +spec: + clusterIP: None + ports: + - name: "80" + port: 80 + targetPort: 80 + selector: + app.service: {{ .Values.resourcePrefix }}varnish +status: + loadBalancer: {} +{{ end }} diff --git a/helm/app/templates/service/varnish/service.yaml b/helm/app/templates/service/varnish/service.yaml new file mode 100644 index 00000000..2b245fbe --- /dev/null +++ b/helm/app/templates/service/varnish/service.yaml @@ -0,0 +1,17 @@ +{{ if .Values.service.varnish | default .Values.docker.services.varnish.enabled }} +apiVersion: v1 +kind: Service +metadata: + labels: + app.service: {{ .Values.resourcePrefix }}varnish + name: {{ .Values.resourcePrefix }}varnish +spec: + ports: + - name: "80" + port: 80 + targetPort: 80 + selector: + app.service: {{ .Values.resourcePrefix }}varnish +status: + loadBalancer: {} +{{ end }} diff --git a/helm/app/templates/service/varnish/statefulset.yaml b/helm/app/templates/service/varnish/statefulset.yaml new file mode 100644 index 00000000..75582637 --- /dev/null +++ b/helm/app/templates/service/varnish/statefulset.yaml @@ -0,0 +1,56 @@ +{{- with .Values.docker.services.varnish -}} +{{- if $.Values.service.varnish | default .enabled -}} +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ $.Values.resourcePrefix }}varnish + annotations: + argocd.argoproj.io/sync-wave: "4" + labels: + app.service: {{ $.Values.resourcePrefix }}varnish +spec: + replicas: {{ $.Values.replicas.varnish }} + podManagementPolicy: Parallel + selector: + matchLabels: + app.service: {{ $.Values.resourcePrefix }}varnish + serviceName: {{ $.Values.resourcePrefix }}varnish-headless + template: + metadata: + creationTimestamp: null + annotations: + checksum/config: {{ include (print $.Template.BasePath "/service/varnish/configmap.yaml") $ | sha256sum }} + labels: + app.service: {{ $.Values.resourcePrefix }}varnish + spec: + containers: + - name: varnish + image: {{ .image | quote }} + imagePullPolicy: Always + ports: + - containerPort: 80 + resources: + limits: + memory: {{ $.Values.resources.memory.varnish | default .resources.memory }} + requests: + memory: {{ $.Values.resources.memory.varnish | default .resources.memory }} + readinessProbe: + tcpSocket: + port: 80 + initialDelaySeconds: 5 + periodSeconds: 10 + volumeMounts: + - name: {{ $.Values.resourcePrefix }}varnish-configuration + mountPath: /etc/varnish/ + - name: {{ $.Values.resourcePrefix }}varnish-cache + mountPath: /var/lib/varnish + restartPolicy: Always + volumes: + - name: {{ $.Values.resourcePrefix }}varnish-configuration + configMap: + name: {{ $.Values.resourcePrefix }}varnish-configuration + - name: {{ $.Values.resourcePrefix }}varnish-cache + emptyDir: + medium: Memory +{{- end }} +{{- end }} diff --git a/helm/app/values-preview.yaml.twig b/helm/app/values-preview.yaml.twig new file mode 100644 index 00000000..85a24145 --- /dev/null +++ b/helm/app/values-preview.yaml.twig @@ -0,0 +1,11 @@ +{% if @('pipeline.preview.services') %} +docker: + services: {{ to_nice_yaml(@('pipeline.preview.services'), 2, 4) | raw }} +{% endif %} +{% if @('pipeline.preview.persistence') %} +persistence: {{ to_nice_yaml(@('pipeline.preview.persistence'), 2, 2) | raw }} +{% endif %} + +{% if @('pipeline.preview.resources') %} +resources: {{ to_nice_yaml(@('pipeline.preview.resources'), 2, 2) | raw }} +{% endif %} diff --git a/helm/app/values-production.yaml.twig b/helm/app/values-production.yaml.twig new file mode 100644 index 00000000..0444d6b2 --- /dev/null +++ b/helm/app/values-production.yaml.twig @@ -0,0 +1,14 @@ +# deprecated, use docker.services.*.enabled instead +service: {} + +{% if @('pipeline.production.services') %} +docker: + services: {{ to_nice_yaml(@('pipeline.production.services'), 2, 4) | raw }} +{% endif %} +{% if @('pipeline.production.persistence') %} +persistence: {{ to_nice_yaml(@('pipeline.production.persistence'), 2, 2) | raw }} +{% endif %} + +{% if @('pipeline.production.resources') %} +resources: {{ to_nice_yaml(@('pipeline.production.resources'), 2, 2) | raw }} +{% endif %} diff --git a/helm/qa/Chart.yaml.twig b/helm/qa/Chart.yaml.twig new file mode 100644 index 00000000..2afdc865 --- /dev/null +++ b/helm/qa/Chart.yaml.twig @@ -0,0 +1,5 @@ +name: {{ @('workspace.name') }}-qa +description: Base helm chart for the {{ @('workspace.name') }}-qa environment +version: 0.0.1 +sources: +home: diff --git a/helm/qa/requirements.yaml.twig b/helm/qa/requirements.yaml.twig new file mode 100644 index 00000000..16b0aa8c --- /dev/null +++ b/helm/qa/requirements.yaml.twig @@ -0,0 +1,4 @@ +dependencies: +- name: {{ @('workspace.name') }} + version: 0.0.1 + repository: "file://../app" diff --git a/mutagen.yml.twig b/mutagen.yml.twig new file mode 100644 index 00000000..d09a48d6 --- /dev/null +++ b/mutagen.yml.twig @@ -0,0 +1,30 @@ +forward: + {{ @('workspace.name') }}: + source: "tcp:localhost:6060" + destination: "docker://{{ @('workspace.name') }}-sync:tcp:localhost:6060" + +sync: + {{ @('workspace.name') }}: + alpha: "." + beta: "docker://{{ @('workspace.name') }}-sync/app" + mode: "two-way-resolved" + # Configuration for host file system as configured above for "alpha" key + configurationAlpha: + permissions: + defaultFileMode: 0644 + defaultDirectoryMode: 0755 + # Configuration for docker file system as configured above for "beta" key + configurationBeta: + permissions: + defaultOwner: "id:1000" + defaultGroup: "id:1000" + defaultFileMode: 0644 + defaultDirectoryMode: 0755 + symlink: + mode: posix-raw + ignore: + paths: + - /.docker-sync + - /.idea + - /.git + - /var