import files

This commit is contained in:
Yann Autissier
2021-02-09 17:05:00 +01:00
parent f5c4576411
commit 44a6d37ba5
425 changed files with 23195 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
##
# APP
.PHONY: start-up
start-up:
+3
View File
@@ -0,0 +1,3 @@
BUILD_APP_VARS ?= APP BRANCH COMMIT DEPLOY_SLACK_HOOK ENV VERSION
COMPOSE_IGNORE_ORPHANS ?= false
ENV_VARS += CONSUL_HTTP_TOKEN
+46
View File
@@ -0,0 +1,46 @@
##
# BUILD
# target build: Build application docker images on local host
.PHONY: build
build: docker-compose-build ## Build application docker images
# target build@%: Build application docker images to deploy
.PHONY: build@% app-build
build@%: infra-base
$(eval DRYRUN_IGNORE := true)
$(eval SERVICES ?= $(shell $(call docker-compose,--log-level critical config --services)))
$(eval DRYRUN_IGNORE := false)
$(eval docker_images += $(foreach service,$(SERVICES),$(if $(shell docker images -q $(DOCKER_REPOSITORY)/$(service):$(DOCKER_IMAGE_TAG) 2>/dev/null),$(service))))
$(eval build_app := $(or $(filter $(DOCKER_BUILD_CACHE),false),$(filter-out $(docker_images),$(SERVICES))))
$(if $(build_app),$(call make,app-build),$(if $(filter $(VERBOSE),true),$(foreach service,$(SERVICES),echo "docker image $(DOCKER_REPOSITORY)/$(service):$(DOCKER_IMAGE_TAG) has id $(shell docker images -q $(DOCKER_REPOSITORY)/$(service):$(DOCKER_IMAGE_TAG) 2>/dev/null)" &&) true))
# target build-env: Build .env file in docker $(SERVICE) to deploy
.PHONY: build-env
build-env: SERVICE ?= $(DOCKER_SERVICE)
build-env: bootstrap
$(call docker-compose-exec,$(SERVICE),rm -f .env && make .env ENV=$(ENV) && echo BUILD=true >> .env && echo BUILD_DATE='"\'"'$(shell date "+%d/%m/%Y %H:%M:%S %z" 2>/dev/null)'"\'"' >> .env && echo BUILD_STATUS='"\'"'$(shell git status -uno --porcelain 2>/dev/null)'"\'"' >> .env && echo DOCKER=false >> .env && $(foreach var,$(BUILD_APP_VARS),$(if $($(var)),sed -i '/^$(var)=/d' .env && echo $(var)='$($(var))' >> .env &&)) true)
# target build-rm: Empty build directory
.PHONY: build-rm
build-rm:
$(call exec,rm -rf build && mkdir -p build)
# target build-$(SHARED): Create shared folder in docker $(SERVICE) to deploy
.PHONY: build-$(SHARED)
build-$(SHARED): SERVICE ?= $(DOCKER_SERVICE)
build-$(SHARED): bootstrap
$(call docker-compose-exec,$(SERVICE),mkdir -p /$(SHARED) && $(foreach folder,$(SHARED_FOLDERS),rm -rf $(folder) && mkdir -p $(dir $(folder)) && ln -s /$(SHARED)/$(notdir $(folder)) $(folder) &&) true)
# target rebuild: Rebuild application docker images on local host
.PHONY: rebuild
rebuild: docker-compose-rebuild ## Rebuild application dockers images
# target rebuild@%: Rebuild application docker images on local host
.PHONY: rebuild@%
rebuild@%: ## Rebuild application dockers images
$(call make,build@$* DOCKER_BUILD_CACHE=false)
# target rebuild-images: Rebuild docker/* images
.PHONY: rebuild-images
rebuild-images: docker-rebuild-images ## Rebuild docker/* images
+14
View File
@@ -0,0 +1,14 @@
##
# CLEAN
.PHONY: clean app-clean
clean: app-clean docker-compose-down clean-env ## Clean application and docker images
# target clean@%: Clean deployed application and docker images
.PHONY: clean@%
clean@%:
$(call make,docker-compose-down DOCKER_COMPOSE_DOWN_OPTIONS='--rmi all -v')
.PHONY: clean-env
clean-env:
rm -i .env || true
+124
View File
@@ -0,0 +1,124 @@
##
# COMMON
.PHONY: bootstrap
bootstrap: bootstrap-git bootstrap-docker ## Bootstrap application
.PHONY: boostrap-docker
bootstrap-docker: docker-network-create
$(if $(filter bootstrap-$(APP),$(MAKETARGETS)),$(call make,bootstrap-$(APP)))
$(call make,docker-compose-up)
.PHONY: bootstrap-git
bootstrap-git:
ifneq ($(SUBREPO),)
if ! git config remote.subrepo/$(SUBREPO).url > /dev/null ; \
then git remote add subrepo/$(SUBREPO) $(GIT_REPOSITORY); \
fi
endif
.PHONY: config
config: docker-compose-config ## View docker compose file
.PHONY: connect
connect: docker-compose-connect ## Connect to docker $(SERVICE)
.PHONY: connect@%
connect@%: SERVICE ?= $(DOCKER_SERVICE)
connect@%: ## Connect to docker $(SERVICE) on first remote host
$(call make,ssh-connect,../infra,APP SERVICE)
.PHONY: down
down: docker-compose-down ## Remove application dockers
.PHONY: exec
exec: ## Exec a command in docker $(SERVICE)
ifneq (,$(filter $(ENV),$(ENV_DEPLOY)))
$(call exec,$(ARGS))
else
$(call make,docker-compose-exec,,ARGS)
endif
.PHONY: exec@%
exec@%: SERVICE ?= $(DOCKER_SERVICE)
exec@%: ## Exec a command in docker $(SERVICE) on all remote hosts
$(call make,ssh-exec,../infra,APP ARGS SERVICE)
.PHONY: logs
logs: docker-compose-logs ## Display application dockers logs
.PHONY: ps
ps: docker-compose-ps ## List application dockers
.PHONY: recreate
recreate: docker-compose-recreate start-up ## Recreate application dockers
.PHONY: reinstall
reinstall: clean ## Reinstall application
$(call make,.env)
$(call make,install)
.PHONY: restart
restart: docker-compose-restart start-up ## Restart application
.PHONY: run
run: ## Run a command in a new docker
ifneq (,$(filter $(ENV),$(ENV_DEPLOY)))
$(call run,$(ARGS))
else
$(call make,docker-compose-run,,ARGS)
endif
.PHONY: run@%
run@%: SERVICE ?= $(DOCKER_SERVICE)
run@%: ## Run a command on all remote hosts
$(call make,ssh-run,../infra,APP ARGS)
.PHONY: scale
scale: docker-compose-scale ## Scale application to NUM dockers
.PHONY: ssh@%
ssh@%: ## Connect to first remote host
$(call make,ssh,../infra,APP)
# target stack: Call docker-stack function with each value of $(STACK)
.PHONY: stack
stack:
$(foreach stackz,$(STACK),$(call docker-stack,$(stackz)))
# target stack-%: Call docker-compose-* command on a given stack
## ex: calling stack-base-up will fire the docker-compose-up target on the base stack
## it splits $* on dashes and extracts stack from the beginning of $* and command
## from the last part of $*
.PHONY: stack-%
stack-%:
$(eval stack := $(subst -$(lastword $(subst -, ,$*)),,$*))
$(eval command := $(lastword $(subst -, ,$*)))
$(if $(findstring -,$*), \
$(if $(filter $(command),$(filter-out %-%,$(patsubst docker-compose-%,%,$(filter docker-compose-%,$(MAKETARGETS))))), \
$(call make,docker-compose-$(command) STACK="$(stack)" $(if $(filter node,$(stack)),COMPOSE_PROJECT_NAME=$(COMPOSE_PROJECT_NAME_INFRA_NODE)),,ARGS COMPOSE_IGNORE_ORPHANS SERVICE)))
.PHONY: start
start: docker-compose-start ## Start application dockers
.PHONY: stop
stop: docker-compose-stop ## Stop application dockers
.PHONY: tests app-tests
tests: app-tests ## Test application
.PHONY: up
up: docker-compose-up start-up ## Create application dockers
.PHONY: update app-update
update: app-update ## Update application
# target %: Always fired target
## this target is fired everytime make is runned to call the stack target and
## update COMPOSE_FILE variable with all .yml files of the current project stack
.PHONY: FORCE
%: FORCE stack %-rule-exists ;
# target %-rule-exists: Print a warning message if $* target does not exists
%-rule-exists:
$(if $(filter $*,$(MAKECMDGOALS)),$(if $(filter-out $*,$(MAKETARGETS)),printf "${COLOR_BROWN}WARNING${COLOR_RESET}: ${COLOR_GREEN}target${COLOR_RESET} $* ${COLOR_GREEN}not available in app${COLOR_RESET} $(APP).\n" >&2))
+34
View File
@@ -0,0 +1,34 @@
CODEDEPLOY_APP_NAME ?= $(APP)
CODEDEPLOY_DEPLOYMENT_GROUP ?= $(CODEDEPLOY_APP_NAME)_$(ENV)
CODEDEPLOY_DEPLOYMENT_CONFIG ?= CodeDeployDefault.AllAtOnce
CODEDEPLOY_DESCRIPTION ?= deploy $(ENV) $(APP) branch: $(BRANCH) commit: $(SUBREPO_COMMIT) tag: $(TAG) version: $(VERSION)
CODEDEPLOY_GITHUB_REPO ?= $(patsubst ssh://git@github.com/%,%,$(GIT_REPOSITORY))
CODEDEPLOY_GITHUB_COMMIT_ID ?= $(SUBREPO_COMMIT)
DEPLOY ?= false
DEPLOY_PING_TEXT ?= app: *$(APP)* branch: *$(BRANCH)* env: *$(ENV)* version: *$(VERSION)* container: *$(CONTAINER)* host: *$(HOST)*
DEPLOY_SLACK_HOOK ?= https://hooks.slack.com/services/123456789/123456789/ABCDEFGHIJKLMNOPQRSTUVWX
HASH ?= $(shell date +%s)
SERVER_NAME ?= $(DOCKER_REGISTRY_USERNAME).$(ENV).$(APP)
OXA_SERVER_NAME ?= web
ifeq ($(APP),marketplace)
CODEDEPLOY_APP_NAME := front
EC2_SERVER_NAME := front
else ifeq ($(APP),medias)
CODEDEPLOY_APP_NAME := apimedia
EC2_SERVER_NAME := api
else ifeq ($(APP),partners)
CODEDEPLOY_APP_NAME := api
EC2_SERVER_NAME := api
else ifeq ($(APP),workers)
CODEDEPLOY_APP_NAME := worker
EC2_SERVER_NAME := worker
endif
ifeq ($(ENV), preprod)
CODEDEPLOY_APP_NAME := $(CODEDEPLOY_APP_NAME)pp
CODEDEPLOY_DEPLOYMENT_GROUP := $(CODEDEPLOY_APP_NAME)_preprod
OXA_SERVER_NAME := $(EC2_SERVER_NAME)pp-0x
else ifeq ($(ENV), prod)
CODEDEPLOY_DEPLOYMENT_GROUP := $(CODEDEPLOY_APP_NAME)_prod
OXA_SERVER_NAME := $(EC2_SERVER_NAME)-xx
endif
+154
View File
@@ -0,0 +1,154 @@
CMDS += docker-compose-exec docker-run docker-run-%
COMPOSE_FILE ?= $(wildcard docker/docker-compose.yml $(foreach file,$(patsubst docker/docker-compose.%,%,$(basename $(wildcard docker/docker-compose.*.yml))),$(if $(filter true,$(COMPOSE_FILE_$(file)) $(COMPOSE_FILE_$(call UPPERCASE,$(file)))),docker/docker-compose.$(file).yml)))
COMPOSE_FILE_$(ENV) ?= true
COMPOSE_FILE_DEBUG ?= $(DEBUG)
COMPOSE_FILE_NFS ?= $(MOUNT_NFS)
COMPOSE_FILE_SSH ?= true
ifneq ($(SUBREPO),)
COMPOSE_FILE_SUBREPO ?= true
else
COMPOSE_FILE_APP ?= true
endif
ifneq (,$(filter $(ENV),$(ENV_DEPLOY)))
COMPOSE_FILE_TMPFS ?= false
else
COMPOSE_FILE_TMPFS ?= true
endif
COMPOSE_PROJECT_NAME ?= $(USER)_$(ENV)_$(APP)
COMPOSE_SERVICE_NAME ?= $(subst _,-,$(COMPOSE_PROJECT_NAME))
CONTEXT += COMPOSE_FILE COMPOSE_PROJECT_NAME DOCKER_IMAGE_TAG DOCKER_REPOSITORY DOCKER_SERVICE
DOCKER_BUILD_ARGS ?= $(if $(filter $(DOCKER_BUILD_NO_CACHE),true),--pull --no-cache) $(foreach var,$(DOCKER_BUILD_VARS),$(if $($(var)),--build-arg $(var)='$($(var))'))
DOCKER_BUILD_CACHE ?= true
DOCKER_BUILD_NO_CACHE ?= false
DOCKER_BUILD_TARGET ?= $(if $(filter $(ENV),$(DOCKER_BUILD_TARGETS)),$(ENV),$(DOCKER_BUILD_TARGET_DEFAULT))
DOCKER_BUILD_TARGET_DEFAULT ?= local
DOCKER_BUILD_TARGETS ?= local debug tests preprod prod
DOCKER_BUILD_VARS ?= APP BRANCH DOCKER_GID DOCKER_REPOSITORY GID GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME TARGET UID USER VERSION
DOCKER_COMPOSE_DOWN_OPTIONS ?=
DOCKER_COMPOSE_UP_OPTIONS ?= -d
DOCKER_GID ?= $(call getent-group,docker)
DOCKER_IMAGE_TAG ?= $(if $(filter-out $(APP),infra),$(if $(filter $(ENV),$(ENV_DEPLOY)),$(VERSION),$(if $(DRONE_BUILD_NUMBER),$(DRONE_BUILD_NUMBER),latest)),latest)
DOCKER_IMAGES ?= $(patsubst %/,%,$(patsubst docker/%,%,$(dir $(wildcard docker/*/Dockerfile))))
DOCKER_PLUGIN ?= rexray/s3fs:latest
DOCKER_PLUGIN_ARGS ?= $(foreach var,$(DOCKER_PLUGIN_VARS),$(if $(DOCKER_PLUGIN_$(var)),$(var)='$(DOCKER_PLUGIN_$(var))'))
DOCKER_PLUGIN_OPTIONS ?= --grant-all-permissions
DOCKER_PLUGIN_S3FS_ACCESSKEY ?= $(shell $(call conf,$(HOME)/.aws/credentials,$(or $(AWS_PROFILE),default),aws_access_key_id))
DOCKER_PLUGIN_S3FS_OPTIONS ?= allow_other,nonempty,use_path_request_style,url=https://s3-eu-west-1.amazonaws.com
DOCKER_PLUGIN_S3FS_SECRETKEY ?= $(shell $(call conf,$(HOME)/.aws/credentials,$(or $(AWS_PROFILE),default),aws_secret_access_key))
DOCKER_PLUGIN_S3FS_REGION ?= eu-west-1
DOCKER_PLUGIN_VARS ?= S3FS_ACCESSKEY S3FS_OPTIONS S3FS_SECRETKEY S3FS_REGION
DOCKER_REGISTRY ?= registry
DOCKER_REGISTRY_USERNAME ?= $(USER)
DOCKER_REGISTRY_REPOSITORY ?= $(addsuffix /,$(DOCKER_REGISTRY))$(subst $(USER),$(DOCKER_REGISTRY_USERNAME),$(DOCKER_REPOSITORY))
DOCKER_REPOSITORY ?= $(subst _,/,$(COMPOSE_PROJECT_NAME))
DOCKER_SHELL ?= $(SHELL)
ENV_VARS += COMPOSE_PROJECT_NAME COMPOSE_SERVICE_NAME DOCKER_BUILD_TARGET DOCKER_GID DOCKER_HOST_IFACE DOCKER_HOST_INET DOCKER_IMAGE_TAG DOCKER_REGISTRY DOCKER_REPOSITORY DOCKER_SHELL
# https://github.com/docker/libnetwork/pull/2348
ifeq ($(HOST_SYSTEM), DARWIN)
DOCKER_HOST_IFACE ?= $(shell docker run --rm -it --net=host alpine /sbin/ip -4 route list match 0/0 2>/dev/null |awk '{print $$5}' |awk '!seen[$$0]++' |head -1)
DOCKER_HOST_INET ?= $(shell docker run --rm -it --net=host alpine /sbin/ip -4 addr show $(DOCKER_HOST_IFACE) 2>/dev/null |awk '$$1 == "inet" {sub(/\/.*/,"",$$2); print $$2}')
DOCKER_INTERNAL_DOCKER_GATEWAY ?= $(shell docker run --rm -it alpine getent hosts gateway.docker.internal |awk '{print $$1}' |head -1)
DOCKER_INTERNAL_DOCKER_HOST ?= $(shell docker run --rm -it alpine getent hosts host.docker.internal |awk '{print $$1}' |head -1)
else
DOCKER_HOST_IFACE ?= $(shell /sbin/ip -4 route list match 0/0 2>/dev/null |awk '{print $$5}' |awk '!seen[$$0]++' |head -1)
DOCKER_HOST_INET ?= $(shell /sbin/ip -4 addr show $(DOCKER_HOST_IFACE) 2>/dev/null |awk '$$1 == "inet" {sub(/\/.*/,"",$$2); print $$2}')
DOCKER_INTERNAL_DOCKER_GATEWAY ?= $(shell /sbin/ip -4 route list match 0/0 2>/dev/null |awk '{print $$3}' |awk '!seen[$$0]++' |head -1)
DOCKER_INTERNAL_DOCKER_HOST ?= $(shell /sbin/ip addr show docker0 2>/dev/null |awk '$$1 == "inet" {sub(/\/.*/,"",$$2); print $$2}')
endif
ifeq ($(DRONE), true)
DOCKER_COMPOSE_DOWN_OPTIONS := --rmi all -v
DOCKER_COMPOSE_UP_OPTIONS := -d --build
DOCKER_BUILD_CACHE := false
ENV_SUFFIX := $(DRONE_BUILD_NUMBER)
ifneq ($(APP), infra)
COMPOSE_PROJECT_NAME := $(USER)_$(ENV)$(ENV_SUFFIX)_$(APP)
COMPOSE_SERVICE_NAME := $(subst _,-,$(COMPOSE_PROJECT_NAME))
DOCKER_REPOSITORY := $(USER)/$(ENV)/$(APP)
endif
endif
ifeq ($(DOCKER), true)
define docker-compose
$(call run,docker/compose:$(COMPOSE_VERSION) $(patsubst %,-f %,$(COMPOSE_FILE)) -p $(COMPOSE_PROJECT_NAME) $(1))
endef
define docker-compose-exec
$(call run,docker/compose:$(COMPOSE_VERSION) $(patsubst %,-f %,$(COMPOSE_FILE)) -p $(COMPOSE_PROJECT_NAME) exec -T $(1) sh -c '$(2)')
endef
else
SHELL := /bin/bash
define docker-compose
$(call run,docker-compose $(patsubst %,-f %,$(COMPOSE_FILE)) -p $(COMPOSE_PROJECT_NAME) $(1))
endef
define docker-compose-exec
$(call run,docker-compose $(patsubst %,-f %,$(COMPOSE_FILE)) -p $(COMPOSE_PROJECT_NAME) exec -T $(1) sh -c '$(2)')
endef
endif
define docker-build
$(eval path := $(patsubst %/,%,$(1)))
$(eval tag := $(or $(2),$(DOCKER_REPOSITORY)/$(lastword $(subst /, ,$(path))):$(DOCKER_IMAGE_TAG)))
$(eval target := $(subst ",,$(subst ',,$(or $(3),$(DOCKER_BUILD_TARGET)))))
$(eval image_id := $(shell docker images -q $(tag) 2>/dev/null))
$(eval build_image := $(or $(filter $(DOCKER_BUILD_CACHE),false),$(if $(image_id),,true)))
$(if $(build_image),$(ECHO) docker build $(DOCKER_BUILD_ARGS) --build-arg DOCKER_BUILD_DIR="$(path)" --tag $(tag) $(if $(target),--target $(target)) -f $(path)/Dockerfile .,$(if $(filter $(VERBOSE),true),echo "docker image $(tag) has id $(image_id)",true))
endef
define docker-commit
$(eval service := $(or $(1),$(DOCKER_SERVICE)))
$(eval container := $(or $(2),$(firstword $(shell $(call docker-compose,--log-level critical ps -q $(service))))))
$(eval repository := $(or $(3),$(DOCKER_REPOSITORY)/$(service)))
$(eval tag := $(or $(4),$(DOCKER_IMAGE_TAG)))
$(if $(filter $(VERBOSE),true),echo docker commit $(container) $(repository):$(tag))
$(ECHO) docker commit $(container) $(repository):$(tag)
endef
define docker-push
$(eval service := $(or $(1),$(DOCKER_SERVICE)))
$(eval name := $(or $(2),$(DOCKER_REGISTRY_REPOSITORY)/$(service)))
$(eval tag := $(or $(3),$(DOCKER_IMAGE_TAG)))
$(if $(filter $(VERBOSE),true),echo docker push $(name):$(tag))
$(ECHO) docker push $(name):$(tag)
endef
##
# docker-stack
# docker-stack: if 1st arg is a variable and can be expand to values, it calls
# itself again, once whith each value, else calls docker-stack-update function
# 1st arg: stacks, extract it from stack_names:stack_versions
# 2nd arg: versions, extract it from stack_names:stack_versions or 2nd arg
define docker-stack
$(eval stacks := $(firstword $(subst :, ,$(1))))
$(eval versions := $(or $(if $(findstring :,$(1)),$(lastword $(subst :, ,$(1)))),$(2)))
$(if $($(stacks)),$(foreach substack,$($(stacks)),$(call docker-stack,$(substack),$(if $(findstring :,$(1)),$(versions)))),$(call docker-stack-update,$(stacks),$(versions)))
endef
##
# docker-stack-update
# docker-stack-update: adds all .yml files of the stack to COMPOSE_FILE variable
# and update the .env file with the .env.dist files of the stack
# 1st arg: stack_path/stack_name:stack_version
# stack: get stack_name:stack_version from 1st arg
# name: get stack name from $(stack)
# 2nd arg: stack version, or extract it from $(stack), default to latest
# 3rd arg: stack path, or extract it from $(stack), default to stack/$(name)
# add $(path)/$(name).yml, $(path)/$(name).$(ENV).yml and $(path)/$(name).$(version).yml to COMPOSE_FILE variable
# if $(path)/.env.dist file exists, update .env file
define docker-stack-update
$(eval stack := $(patsubst %.yml,%,$(notdir $(1))))
$(eval name := $(firstword $(subst :, ,$(stack))))
$(eval version := $(or $(2),$(if $(findstring :,$(stack)),$(lastword $(subst :, ,$(stack))),latest)))
$(eval path := $(patsubst %/,%,$(or $(3),$(if $(findstring /,$(1)),$(if $(wildcard stack/$(1) stack/$(1).yml),stack/$(if $(findstring .yml,$(1)),$(dir $(1)),$(if $(wildcard stack/$(1).yml),$(dir $(1)),$(1))),$(dir $(1)))),stack/$(name))))
$(eval COMPOSE_FILE += $(wildcard $(path)/$(name).yml $(path)/$(name).$(ENV).yml $(path)/$(name).$(ENV).$(version).yml $(path)/$(name).$(version).yml))
$(if $(wildcard $(path)/.env.dist),$(call .env,,$(path)/.env.dist,$(wildcard ../$(PARAMETERS)/$(ENV)/$(APP)/.env $(path)/.env.$(ENV) .env)))
endef
define docker-tag
$(eval service := $(or $(1),$(DOCKER_SERVICE)))
$(eval source := $(or $(2),$(DOCKER_REPOSITORY)/$(service)))
$(eval source_tag := $(or $(3),$(DOCKER_IMAGE_TAG)))
$(eval target := $(or $(4),$(DOCKER_REGISTRY_REPOSITORY)/$(service)))
$(eval target_tag := $(or $(5),$(source_tag)))
$(if $(filter $(VERBOSE),true),echo docker tag $(source):$(source_tag) $(target):$(target_tag))
$(ECHO) docker tag $(source):$(source_tag) $(target):$(target_tag)
endef
+7
View File
@@ -0,0 +1,7 @@
define install-parameters
$(eval path:=$(or $(1),$(APP)))
$(eval file:=$(or $(2),$(DOCKER_SERVICE)/parameters.yml))
$(eval dest:=$(or $(3),app/config))
$(eval env:=$(or $(4),$(ENV)))
$(if $(wildcard $(dest)/$(file)),,$(if $(wildcard ../$(PARAMETERS)/$(env)/$(path)/$(file)),$(ECHO) cp -a ../$(PARAMETERS)/$(env)/$(path)/$(file) $(dest)))
endef
+4
View File
@@ -0,0 +1,4 @@
ENV_VARS += NFS_CONFIG
MOUNT_NFS ?= false
NFS_CONFIG ?= addr=$(NFS_HOST),actimeo=3,intr,noacl,noatime,nocto,nodiratime,nolock,soft,rsize=32768,wsize=32768,tcp,rw,vers=3
NFS_HOST ?= host.docker.internal
+88
View File
@@ -0,0 +1,88 @@
##########
# DEPLOY #
##########
.PHONY: deploy app-deploy
# target deploy: Run post install hooks in the deployed application
## Called by ansible after creation of the docker application on remote host
deploy: app-deploy ## Run post install hooks in the deployed application
.PHONY: deploy@%
# target deploy@%: Deploy application docker images
## tag and push docker images to docker registry
## run ansible-pull on hosts to pull docker images from the registry
## tag and push docker images as latest to docker registry
deploy@%: infra-base build@% ## Deploy application docker images
$(call make,docker-login docker-tag docker-push)
$(call make,infra-ansible-pull@$(ENV) ANSIBLE_DOCKER_IMAGE_TAG=$(VERSION) ANSIBLE_TAGS=aws,,APP AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY)
$(call make,docker-tag-latest docker-push-latest)
.PHONY: deploy-aws-codedeploy-%
deploy-aws-codedeploy-%:
$(call exec,git fetch subrepo/$(SUBREPO))
ifneq ($(wildcard ../infra),)
$(call make,aws-codedeploy,../infra,CODEDEPLOY_APP_NAME CODEDEPLOY_DEPLOYMENT_CONFIG CODEDEPLOY_DEPLOYMENT_GROUP CODEDEPLOY_DESCRIPTION CODEDEPLOY_GITHUB_REPO CODEDEPLOY_GITHUB_COMMIT_ID)
endif
.PHONY: deploy-assets-install
deploy-assets-install:
su -s /bin/sh www-data -c "php app/console --no-interaction assets:install --env=prod"
su -s /bin/sh www-data -c "php app/console --no-interaction assetic:dump --env=prod"
.PHONY: deploy-cache-clear
deploy-cache-clear:
su -s /bin/sh www-data -c "php app/console --no-interaction cache:clear --env=prod"
.PHONY: deploy-cache-warmup
deploy-cache-warmup:
su -s /bin/sh www-data -c "php app/console --no-interaction cache:warmup --env=prod"
.PHONY: deploy-composer
deploy-composer:
su -s /bin/sh www-data -c "composer install --prefer-dist --optimize-autoloader --no-progress --no-interaction --no-dev"
.PHONY: deploy-doctrine-migrations-migrate
deploy-doctrine-migrations-migrate:
su -s /bin/sh www-data -c "php app/console --no-interaction doctrine:migrations:migrate"
.PHONY: deploy-npm
deploy-npm: deploy-npm-install deploy-npm-run-build
.PHONY: deploy-npm-install
deploy-npm-install:
npm set progress=false
npm install -s
.PHONY: deploy-npm-run-build
deploy-npm-run-build:
npm run build:prod
.PHONY: deploy-ping
deploy-ping: deploy-ping-slack
.PHONY: deploy-ping-slack
deploy-ping-slack:
curl -X POST --data-urlencode 'payload={"text": "$(DEPLOY_PING_TEXT)"}' $(DEPLOY_SLACK_HOOK) ||:
.PHONY: deploy-supervisorctl-restart-all
deploy-supervisorctl-restart-all:
supervisorctl restart all
.PHONY: deploy-supervisorctl-start-all
deploy-supervisorctl-start-all:
supervisorctl start all
.PHONY: deploy-supervisorctl-stop-all
deploy-supervisorctl-stop-all:
supervisorctl stop all
.PHONY: deploy-yarn
deploy-yarn: deploy-yarn-install
.PHONY: deploy-yarn-build
deploy-yarn-build:
yarn build:prod
.PHONY: deploy-yarn-install
deploy-yarn-install:
yarn install
+211
View File
@@ -0,0 +1,211 @@
##
# DOCKER
.PHONY: docker-build
docker-build: docker-images-infra
$(foreach image,$(or $(SERVICE),$(DOCKER_IMAGES)),$(call make,docker-build-$(image)))
.PHONY: docker-build-%
docker-build-%:
if grep -q DOCKER_REPOSITORY docker/$*/Dockerfile 2>/dev/null; then $(eval DOCKER_BUILD_ARGS:=$(subst $(DOCKER_REPOSITORY),$(DOCKER_REPOSITORY_INFRA),$(DOCKER_BUILD_ARGS))) true; fi
$(if $(wildcard docker/$*/Dockerfile),$(call docker-build,docker/$*))
$(if $(findstring :,$*),$(eval DOCKERFILES := $(wildcard docker/$(subst :,/,$*)/Dockerfile)),$(eval DOCKERFILES := $(wildcard docker/$*/*/Dockerfile)))
$(foreach dockerfile,$(DOCKERFILES),$(call docker-build,$(dir $(dockerfile)),$(DOCKER_REPOSITORY)/$(word 2,$(subst /, ,$(dir $(dockerfile)))):$(lastword $(subst /, ,$(dir $(dockerfile)))),"") && true)
.PHONY: docker-commit
docker-commit:
$(eval DRYRUN_IGNORE := true)
$(eval SERVICES ?= $(shell $(call docker-compose,--log-level critical config --services)))
$(eval DRYRUN_IGNORE := false)
$(foreach service,$(or $(SERVICE),$(SERVICES)),$(call docker-commit,$(service)))
.PHONY: docker-commit-%
docker-commit-%:
$(eval DRYRUN_IGNORE := true)
$(eval SERVICES ?= $(shell $(call docker-compose,--log-level critical config --services)))
$(eval DRYRUN_IGNORE := false)
$(foreach service,$(or $(SERVICE),$(SERVICES)),$(call docker-commit,$(service),,,$*))
.PHONY: docker-compose-build
docker-compose-build: docker-images-infra
$(eval DRYRUN_IGNORE := true)
$(eval SERVICES ?= $(shell $(call docker-compose,--log-level critical config --services)))
$(eval DRYRUN_IGNORE := false)
$(call docker-compose,build $(if $(filter $(DOCKER_BUILD_NO_CACHE),true),--pull --no-cache) $(if $(filter $(SERVICE),$(SERVICES)),$(SERVICE)))
.PHONY: docker-compose-config
docker-compose-config:
$(call docker-compose,config)
.PHONY: docker-compose-connect
docker-compose-connect: SERVICE ?= $(DOCKER_SERVICE)
docker-compose-connect:
$(call docker-compose,exec $(SERVICE) $(DOCKER_SHELL)) || true
.PHONY: docker-compose-down
docker-compose-down:
$(eval DRYRUN_IGNORE := true)
$(eval SERVICES ?= $(shell $(call docker-compose,--log-level critical config --services)))
$(eval DRYRUN_IGNORE := false)
$(if $(filter $(SERVICE),$(SERVICES)),$(call docker-compose,rm -fs $(SERVICE)),$(call docker-compose,down $(DOCKER_COMPOSE_DOWN_OPTIONS)))
.PHONY: docker-compose-exec
docker-compose-exec: SERVICE ?= $(DOCKER_SERVICE)
docker-compose-exec:
$(call docker-compose-exec,$(SERVICE),$(ARGS)) || true
.PHONY: docker-compose-logs
docker-compose-logs:
$(eval DRYRUN_IGNORE := true)
$(eval SERVICES ?= $(shell $(call docker-compose,--log-level critical config --services)))
$(eval DRYRUN_IGNORE := false)
$(call docker-compose,logs -f --tail=100 $(if $(filter $(SERVICE),$(SERVICES)),$(SERVICE))) || true
.PHONY: docker-compose-ps
docker-compose-ps:
$(call docker-compose,ps)
.PHONY: docker-compose-rebuild
docker-compose-rebuild: docker-images-infra
$(call make,docker-compose-build DOCKER_BUILD_NO_CACHE=true)
.PHONY: docker-compose-recreate
docker-compose-recreate: docker-compose-rm docker-compose-up
.PHONY: docker-compose-restart
docker-compose-restart:
$(eval DRYRUN_IGNORE := true)
$(eval SERVICES ?= $(shell $(call docker-compose,--log-level critical config --services)))
$(eval DRYRUN_IGNORE := false)
$(call docker-compose,restart $(if $(filter $(SERVICE),$(SERVICES)),$(SERVICE)))
.PHONY: docker-compose-rm
docker-compose-rm:
$(eval DRYRUN_IGNORE := true)
$(eval SERVICES ?= $(shell $(call docker-compose,--log-level critical config --services)))
$(eval DRYRUN_IGNORE := false)
$(call docker-compose,rm -fs $(if $(filter $(SERVICE),$(SERVICES)),$(SERVICE)))
.PHONY: docker-compose-run
docker-compose-run: SERVICE ?= $(DOCKER_SERVICE)
docker-compose-run:
$(call docker-compose,run $(SERVICE) $(ARGS))
.PHONY: docker-compose-scale
docker-compose-scale: SERVICE ?= $(DOCKER_SERVICE)
docker-compose-scale:
$(call docker-compose,up $(DOCKER_COMPOSE_UP_OPTIONS) --scale $(SERVICE)=$(NUM))
.PHONY: docker-compose-start
docker-compose-start:
$(eval DRYRUN_IGNORE := true)
$(eval SERVICES ?= $(shell $(call docker-compose,--log-level critical config --services)))
$(eval DRYRUN_IGNORE := false)
$(call docker-compose,start $(if $(filter $(SERVICE),$(SERVICES)),$(SERVICE)))
.PHONY: docker-compose-stop
docker-compose-stop:
$(eval DRYRUN_IGNORE := true)
$(eval SERVICES ?= $(shell $(call docker-compose,--log-level critical config --services)))
$(eval DRYRUN_IGNORE := false)
$(call docker-compose,stop $(if $(filter $(SERVICE),$(SERVICES)),$(SERVICE)))
.PHONY: docker-compose-up
docker-compose-up: docker-images-infra
$(eval DRYRUN_IGNORE := true)
$(eval SERVICES ?= $(shell $(call docker-compose,--log-level critical config --services)))
$(eval DRYRUN_IGNORE := false)
$(call docker-compose,up $(DOCKER_COMPOSE_UP_OPTIONS) $(if $(filter $(SERVICE),$(SERVICES)),$(SERVICE)))
.PHONY: docker-images-infra
docker-images-infra:
$(foreach image,$(subst $(quote),,$(DOCKER_IMAGES_INFRA)),$(call make,infra-docker-build-$(image)))
.PHONY: docker-login
docker-login: infra-aws-ecr-login
.PHONY: docker-network-create
docker-network-create: docker-network-create-$(DOCKER_NETWORK)
.PHONY: docker-network-create-%
docker-network-create-%:
[ -n "$(shell docker network ls -q --filter name='^$*$$' 2>/dev/null)" ] \
|| { echo -n "Creating docker network $* ... " && $(ECHO) docker network create $* >/dev/null 2>&1 && echo "done" || echo "ERROR"; }
.PHONY: docker-network-rm
docker-network-rm: docker-network-rm-$(DOCKER_NETWORK)
.PHONY: docker-network-rm-%
docker-network-rm-%:
[ -z "$(shell docker network ls -q --filter name='^$*$$' 2>/dev/null)" ] \
|| { echo -n "Removing docker network $* ... " && $(ECHO) docker network rm $* >/dev/null 2>&1 && echo "done" || echo "ERROR"; }
.PHONY: docker-plugin-install
docker-plugin-install:
$(eval docker_plugin_state := $(shell docker plugin ls | awk '$$2 == "$(DOCKER_PLUGIN)" {print $$NF}') )
$(if $(docker_plugin_state),$(if $(filter $(docker_plugin_state),false),echo -n "Enabling docker plugin $(DOCKER_PLUGIN) ... " && $(ECHO) docker plugin enable $(DOCKER_PLUGIN) >/dev/null 2>&1 && echo "done" || echo "ERROR"),echo -n "Installing docker plugin $(DOCKER_PLUGIN) ... " && $(ECHO) docker plugin install $(DOCKER_PLUGIN_OPTIONS) $(DOCKER_PLUGIN) $(DOCKER_PLUGIN_ARGS) >/dev/null 2>&1 && echo "done" || echo "ERROR")
.PHONY: docker-push
docker-push:
ifneq ($(filter $(DEPLOY),true),)
$(eval DRYRUN_IGNORE := true)
$(eval SERVICES ?= $(shell $(call docker-compose,--log-level critical config --services)))
$(eval DRYRUN_IGNORE := false)
$(foreach service,$(or $(SERVICE),$(SERVICES)),$(call docker-push,$(service)))
else
printf "${COLOR_BROWN}WARNING${COLOR_RESET}: ${COLOR_GREEN}target${COLOR_RESET} $@ ${COLOR_GREEN}not enabled in${COLOR_RESET} $(APP).\n" >&2
endif
.PHONY: docker-push-%
docker-push-%:
ifneq ($(filter $(DEPLOY),true),)
$(eval DRYRUN_IGNORE := true)
$(eval SERVICES ?= $(shell $(call docker-compose,--log-level critical config --services)))
$(eval DRYRUN_IGNORE := false)
$(foreach service,$(or $(SERVICE),$(SERVICES)),$(call docker-push,$(service),,$*))
else
printf "${COLOR_BROWN}WARNING${COLOR_RESET}: ${COLOR_GREEN}target${COLOR_RESET} $@ ${COLOR_GREEN}not enabled in${COLOR_RESET} $(APP).\n" >&2
endif
.PHONY: docker-rebuild
docker-rebuild:
$(call make,docker-build DOCKER_BUILD_CACHE=false)
.PHONY: docker-rebuild-%
docker-rebuild-%:
$(call make,docker-build-$* DOCKER_BUILD_CACHE=false)
.PHONY: docker-run
docker-run: SERVICE ?= $(DOCKER_SERVICE)
docker-run:
$(call make,docker-run-$(SERVICE),,ARGS)
.PHONY: docker-run-%
docker-run-%: docker-build-%
$(eval command := $(ARGS))
$(eval path := $(patsubst %/,%,$*))
$(eval image := $(DOCKER_REPOSITORY)/$(lastword $(subst /, ,$(path)))$(if $(findstring :,$*),,:$(DOCKER_IMAGE_TAG)))
$(eval image_id := $(shell docker images -q $(image) 2>/dev/null))
$(call docker-run,$(if $(image_id),$(image),$(path)),$(command))
.PHONY: docker-tag
docker-tag:
ifneq ($(filter $(DEPLOY),true),)
$(eval DRYRUN_IGNORE := true)
$(eval SERVICES ?= $(shell $(call docker-compose,--log-level critical config --services)))
$(eval DRYRUN_IGNORE := false)
$(foreach service,$(or $(SERVICE),$(SERVICES)),$(call docker-tag,$(service)))
else
printf "${COLOR_BROWN}WARNING${COLOR_RESET}: ${COLOR_GREEN}target${COLOR_RESET} $@ ${COLOR_GREEN}not enabled in${COLOR_RESET} $(APP).\n" >&2
endif
.PHONY: docker-tag-%
docker-tag-%:
ifneq ($(filter $(DEPLOY),true),)
$(eval DRYRUN_IGNORE := true)
$(eval SERVICES ?= $(shell $(call docker-compose,--log-level critical config --services)))
$(eval DRYRUN_IGNORE := false)
$(foreach service,$(or $(SERVICE),$(SERVICES)),$(call docker-tag,$(service),,,,$*))
else
printf "${COLOR_BROWN}WARNING${COLOR_RESET}: ${COLOR_GREEN}target${COLOR_RESET} $@ ${COLOR_GREEN}not enabled in${COLOR_RESET} $(APP).\n" >&2
endif
+26
View File
@@ -0,0 +1,26 @@
.PHONY: ansible
ansible: docker-build-ansible
ifneq ($(ARGS),)
$(call ansible,$(ANSIBLE_ARGS) $(ARGS))
else
$(call make,ansible-run)
endif
.PHONY: ansible-playbook
ansible-playbook:
$(call ansible-playbook,$(ANSIBLE_ARGS) $(ARGS))
.PHONY: ansible-pull
ansible-pull:
$(call ansible-pull,--url $(ANSIBLE_GIT_REPOSITORY) $(if $(ANSIBLE_GIT_KEY_FILE),--key-file $(ANSIBLE_GIT_KEY_FILE)) $(if $(ANSIBLE_GIT_VERSION),--checkout $(ANSIBLE_GIT_VERSION)) $(if $(ANSIBLE_GIT_DIRECTORY),--directory $(ANSIBLE_GIT_DIRECTORY)) $(if $(ANSIBLE_TAGS),--tags $(ANSIBLE_TAGS)) $(if $(ANSIBLE_EXTRA_VARS),--extra-vars '$(ANSIBLE_EXTRA_VARS)') $(if $(findstring true,$(FORCE)),--force) $(if $(findstring true,$(DRYRUN)),--check) --full $(if $(ANSIBLE_INVENTORY),--inventory $(ANSIBLE_INVENTORY)) $(ANSIBLE_PLAYBOOK))
.PHONY: ansible-pull@%
ansible-pull@%: aws-ec2-get-PrivateIpAddress-$(SERVER_NAME)
$(call ssh-exec,$(AWS_INSTANCE_IP),make ansible-pull ANSIBLE_DOCKER_IMAGE_TAG=$(ANSIBLE_DOCKER_IMAGE_TAG) ANSIBLE_TAGS=$(ANSIBLE_TAGS) FORCE=$(FORCE))
.PHONY: ansible-run
ansible-run: base-ssh-add docker-build-ansible ansible-run-localhost
.PHONY: ansible-run-%
ansible-run-%:
$(call ansible-playbook,$(if $(ANSIBLE_TAGS),--tags $(ANSIBLE_TAGS)) $(if $(ANSIBLE_EXTRA_VARS),--extra-vars '$(patsubst target=localhost,target=$*,$(ANSIBLE_EXTRA_VARS))') $(if $(findstring true,$(DRYRUN)),--check) $(if $(ANSIBLE_INVENTORY),--inventory $(ANSIBLE_INVENTORY)) $(ANSIBLE_PLAYBOOK))
+170
View File
@@ -0,0 +1,170 @@
.PHONY: aws
aws: docker-build-aws
$(call aws,$(ARGS))
.PHONY: aws-codedeploy
aws-codedeploy:
$(call aws,deploy create-deployment \
--application-name $(CODEDEPLOY_APP_NAME) \
--deployment-config-name $(CODEDEPLOY_DEPLOYMENT_CONFIG) \
--deployment-group-name $(CODEDEPLOY_DEPLOYMENT_GROUP) \
--description "$(CODEDEPLOY_DESCRIPTION)" \
--github-location repository=$(CODEDEPLOY_GITHUB_REPO)$(comma)commitId=$(CODEDEPLOY_GITHUB_COMMIT_ID))
.PHONY: aws-role-create-import-image
aws-role-create-import-image: aws-iam-create-role-$(AWS_VM_IMPORT_ROLE_NAME) aws-iam-put-role-policy-$(AWS_VM_IMPORT_ROLE_NAME)
.PHONY: aws-ecr-login
aws-ecr-login:
$(eval DRYRUN_IGNORE := true)
$(eval docker_login := $(shell $(call aws,ecr get-login --no-include-email --region $(AWS_DEFAULT_REGION))))
$(eval DRYRUN_IGNORE := FALSE)
$(ECHO) $(docker_login)
.PHONY: aws-iam-create-role-%
aws-iam-create-role-%: base docker-build-aws
$(eval DRYRUN_IGNORE := true)
$(eval json := $(shell $(call exec,envsubst < aws/policies/$*-trust.json)))
$(eval DRYRUN_IGNORE := false)
$(call aws,iam create-role --role-name $* --assume-role-policy-document '$(json)')
.PHONY: aws-iam-put-role-policy-%
aws-iam-put-role-policy-%: base docker-build-aws
$(eval DRYRUN_IGNORE := true)
$(eval json := $(shell $(call exec,envsubst < aws/policies/$*.json)))
$(eval DRYRUN_IGNORE := false)
$(call aws,iam put-role-policy --role-name $* --policy-name $* --policy-document '$(json)')
.PHONY: aws-s3-check-upload
aws-s3-check-upload: docker-build-aws aws-s3api-head-object-query-etag
$(eval upload := true)
$(eval DRYRUN_IGNORE := true)
$(if $(AWS_S3_KEY_ETAG),$(if $(filter $(AWS_S3_KEY_ETAG),"$(shell cat $(PACKER_ISO_INFO) |awk '$$1 == "etag:" {print $$2}' 2>/dev/null)"),$(eval upload := false)))
$(eval DRYRUN_IGNORE := false)
.PHONY: aws-s3-cp
aws-s3-cp: docker-build-aws $(PACKER_ISO_FILE) aws-s3-check-upload
$(if $(filter $(upload),true),$(call aws,s3 cp $(PACKER_ISO_FILE) s3://$(AWS_S3_BUCKET)/$(AWS_S3_KEY)) $(call make,aws-s3-etag-save))
.PHONY: aws-s3-etag-save
aws-s3-etag-save: docker-build-aws aws-s3api-head-object-query-etag
echo "etag: $(AWS_S3_KEY_ETAG)" >> $(PACKER_ISO_INFO)
.PHONY: aws-s3api-head-object-query-etag
aws-s3api-head-object-query-etag: docker-build-aws
$(eval DRYRUN_IGNORE := true)
$(eval AWS_S3_KEY_ETAG := $(shell $(call aws,s3api head-object --bucket $(AWS_S3_BUCKET) --key $(AWS_S3_KEY) --output text --query ETag) |grep -v 'operation: Not Found' 2>/dev/null))
$(eval DRYRUN_IGNORE := false)
echo ETag: $(AWS_S3_KEY_ETAG)
.PHONY: aws-s3api-head-object-query-lastmodified
aws-s3api-head-object-query-lastmodified: docker-build-aws
$(eval DRYRUN_IGNORE := true)
$(eval AWS_S3_KEY_DATE := $(shell $(call aws,s3api head-object --bucket $(AWS_S3_BUCKET) --key $(AWS_S3_KEY) --output text --query LastModified) |grep -v 'operation: Not Found' 2>/dev/null))
$(eval DRYRUN_IGNORE := false)
echo LastModified: $(AWS_S3_KEY_DATE)
.PHONY: aws-ec2-import-snapshot
aws-ec2-import-snapshot: base docker-build-aws aws-s3api-head-object-query-etag aws-s3api-head-object-query-lastmodified
$(eval DRYRUN_IGNORE := true)
$(eval json := $(shell $(call exec,envsubst < aws/import-snapshot.json)))
$(eval DRYRUN_IGNORE := false)
$(eval AWS_TASK_ID := $(shell $(call aws,ec2 import-snapshot --description '$(AWS_SNAP_DESCRIPTION)' --output text --query ImportTaskId --disk-container '$(json)')))
echo ImportTaskId: $(AWS_TASK_ID)
.PHONY: aws-ec2-describe-import-snapshot-task-%
aws-ec2-describe-import-snapshot-task-%: docker-build-aws
$(call aws,ec2 describe-import-snapshot-tasks --import-task-ids $*)
.PHONY: aws-ec2-describe-import-snapshot-tasks
aws-ec2-describe-import-snapshot-tasks: docker-build-aws
$(call aws,ec2 describe-import-snapshot-tasks)
.PHONY: aws-ec2-describe-instance-PrivateIpAddress
aws-ec2-describe-instance-PrivateIpAddress: docker-build-aws
$(call aws,ec2 describe-instances --no-paginate --query 'Reservations[*].Instances[*].[Tags[?Key==`Name`].Value$(comma)PrivateIpAddress]' --output text) |sed '$$!N;s/\r\n/ /' |awk 'BEGIN {printf "%-24s%s\r\n"$(comma)"PrivateIpAddress"$(comma)"Name"}; $$1 != "None" {printf "%-24s%s\n"$(comma)$$1$(comma)$$2}'
.PHONY: aws-ec2-describe-instance-PrivateIpAddress-%
aws-ec2-describe-instance-PrivateIpAddress-%: docker-build-aws
$(call aws,ec2 describe-instances --no-paginate --query 'Reservations[*].Instances[*].[Tags[?Key==`Name`].Value$(comma)PrivateIpAddress]' --output text) |sed '$$!N;s/\r\n/ /' |awk 'BEGIN {printf "%-24s%s\r\n"$(comma)"PrivateIpAddress"$(comma)"Name"}; $$1 != "None" && $$2 ~ /$*/ {printf "%-24s%s\n"$(comma)$$1$(comma)$$2}'
.PHONY: aws-ec2-get-PrivateIpAddress
aws-ec2-get-PrivateIpAddress: docker-build-aws
$(eval DRYRUN_IGNORE := true)
$(eval AWS_INSTANCE_IP := $(shell $(call aws,ec2 describe-instances --no-paginate --query 'Reservations[*].Instances[*].PrivateIpAddress' --output text) 2>/dev/null))
$(eval DRYRUN_IGNORE := false)
echo PrivateIpAddress: $(AWS_INSTANCE_IP)
.PHONY: aws-ec2-get-PrivateIpAddress-%
aws-ec2-get-PrivateIpAddress-%:
$(eval DRYRUN_IGNORE := true)
$(eval AWS_INSTANCE_IP := $(shell $(call aws,ec2 describe-instances --no-paginate --filter 'Name=tag:Name$(comma)Values=$**' --query 'Reservations[*].Instances[*].PrivateIpAddress' --output text) 2>/dev/null))
$(eval DRYRUN_IGNORE := false)
echo PrivateIpAddress: $(AWS_INSTANCE_IP)
.PHONY: aws-ec2-get-snap-id-import-snapshot-task
aws-ec2-get-snap-id-import-snapshot-task: aws-ec2-get-snap-id-import-snapshot-task-$(AWS_TASK_ID)
.PHONY: aws-ec2-get-snap-id-import-snapshot-task-%
aws-ec2-get-snap-id-import-snapshot-task-%: docker-build-aws
$(eval DRYRUN_IGNORE := true)
$(eval AWS_SNAP_ID := $(shell $(call aws,ec2 describe-import-snapshot-tasks --import-task-ids $* --output text --query ImportSnapshotTasks[0].SnapshotTaskDetail.SnapshotId) 2>/dev/null))
$(eval DRYRUN_IGNORE := false)
echo SnapshotId: $(AWS_SNAP_ID)
.PHONY: aws-ec2-get-snap-message-import-snapshot-task-%
aws-ec2-get-snap-message-import-snapshot-task-%: docker-build-aws
$(eval DRYRUN_IGNORE := true)
$(eval AWS_SNAP_MESSAGE := $(shell $(call aws,ec2 describe-import-snapshot-tasks --import-task-ids $* --output text --query ImportSnapshotTasks[0].SnapshotTaskDetail.StatusMessage) 2>/dev/null))
$(eval DRYRUN_IGNORE := false)
echo StatusMessage: $(AWS_SNAP_MESSAGE)
.PHONY: aws-ec2-get-snap-progress-import-snapshot-task-%
aws-ec2-get-snap-progress-import-snapshot-task-%: docker-build-aws
$(eval DRYRUN_IGNORE := true)
$(eval AWS_SNAP_PROGRESS := $(shell $(call aws,ec2 describe-import-snapshot-tasks --import-task-ids $* --output text --query ImportSnapshotTasks[0].SnapshotTaskDetail.Progress) 2>/dev/null))
$(eval DRYRUN_IGNORE := false)
echo Progress: $(AWS_SNAP_PROGRESS)
.PHONY: aws-ec2-get-snap-size-import-snapshot-task-%
aws-ec2-get-snap-size-import-snapshot-task-%: docker-build-aws
$(eval DRYRUN_IGNORE := true)
$(eval AWS_SNAP_SIZE := $(shell $(call aws,ec2 describe-import-snapshot-tasks --import-task-ids $* --output text --query ImportSnapshotTasks[0].SnapshotTaskDetail.DiskImageSize) 2>/dev/null))
$(eval DRYRUN_IGNORE := false)
echo DiskImageSize: $(AWS_SNAP_SIZE)
.PHONY: aws-ec2-get-snap-status-import-snapshot-task-%
aws-ec2-get-snap-status-import-snapshot-task-%: docker-build-aws
$(eval DRYRUN_IGNORE := true)
$(eval AWS_SNAP_STATUS := $(shell $(call aws,ec2 describe-import-snapshot-tasks --import-task-ids $* --output text --query ImportSnapshotTasks[0].SnapshotTaskDetail.Status) 2>/dev/null))
$(eval DRYRUN_IGNORE := false)
echo Status: $(AWS_SNAP_STATUS)
.PHONY: aws-ec2-wait-snap-completed-import-snapshot-task
aws-ec2-wait-snap-completed-import-snapshot-task: aws-ec2-wait-snap-completed-import-snapshot-task-$(AWS_TASK_ID)
.PHONY: aws-ec2-wait-snap-completed-import-snapshot-task-%
aws-ec2-wait-snap-completed-import-snapshot-task-%: docker-build-aws
while [ `$(call aws,ec2 describe-import-snapshot-tasks --import-task-ids $* --output text --query ImportSnapshotTasks[0].SnapshotTaskDetail.Status)` != "completed$$(printf '\r')" ]; \
do \
count=$$(( $${count:-0}+1 )); \
[ "$${count}" -eq 99 ] && exit 1; \
sleep 10; \
done
.PHONY: aws-ec2-wait-snapshot-%
aws-ec2-wait-snapshot-%: docker-build-aws
$(call aws,ec2 wait snapshot-completed --snapshot-ids $* --output text)
.PHONY: aws-ec2-register-image
aws-ec2-register-image: base docker-build-aws aws-ec2-get-snap-id-import-snapshot-task
$(eval DRYRUN_IGNORE := true)
$(eval json := $(shell $(call exec,envsubst < aws/register-image-device-mappings.json)))
$(eval DRYRUN_IGNORE := false)
$(eval AWS_AMI_ID := $(shell $(call aws,ec2 register-image --name '$(AWS_AMI_NAME)' --description '$(AWS_AMI_DESCRIPTION)' --architecture x86_64 --root-device-name /dev/sda1 --virtualization-type hvm --block-device-mappings '$(json)') 2>/dev/null))
echo ImageId: $(AWS_AMI_ID)
.PHONY: aws-ami
aws-ami: aws-s3-cp aws-ec2-import-snapshot
$(call make,aws-ec2-wait-snap-completed-import-snapshot-task,,AWS_TASK_ID)
$(call make,aws-ec2-register-image,,AWS_TASK_ID)
+10
View File
@@ -0,0 +1,10 @@
##
# BOOTSTRAP
.PHONY: bootstrap-infra
bootstrap-infra: setup-sysctl
ifeq ($(SETUP_NFSD),true)
ifeq ($(HOST_SYSTEM),DARWIN)
$(call setup-nfsd-osx)
endif
endif
+18
View File
@@ -0,0 +1,18 @@
##
# CLEAN
.PHONY: clean-docker-%
clean-docker-%:
docker ps -a |awk '$$NF ~ /_$*/ && $$NF !~ /_infra_/ {print $$NF}' |while read docker; do docker rm -f $$docker; done
.PHONY: clean-elasticsearch-%
clean-elasticsearch-%:
docker ps |awk '$$NF ~ /infra_elasticsearch/' |sed 's/^.*:\([0-9]*\)->9200\/tcp.*$$/\1/' |while read port; do echo -e "DELETE /$* HTTP/1.0\n\n" |nc localhost $$port; done
.PHONY: clean-images-%
clean-images-%:
docker images |awk '$$1 ~ /\/$*/ && $$1 !~ /\/infra\// {print $$3}' |sort -u |while read image; do docker rmi -f $$image; done
.PHONY: clean-volumes-%
clean-volumes-%:
docker volume ls |awk '$$2 ~ /_$*/ && $$2 !~ /_infra_/ {print $$2}' |sort -u |while read volume; do docker volume rm $$volume; done
+50
View File
@@ -0,0 +1,50 @@
ANSIBLE_AWS_ACCESS_KEY_ID ?= $(AWS_ACCESS_KEY_ID)
ANSIBLE_AWS_DEFAULT_OUTPUT ?= $(AWS_DEFAULT_OUTPUT)
ANSIBLE_AWS_DEFAULT_REGION ?= $(AWS_DEFAULT_REGION)
ANSIBLE_AWS_SECRET_ACCESS_KEY ?= $(AWS_SECRET_ACCESS_KEY)
ANSIBLE_CONFIG ?= ansible/ansible.cfg
ANSIBLE_DISKS_NFS_DISK ?= $(NFS_DISK)
ANSIBLE_DISKS_NFS_OPTIONS ?= $(NFS_OPTIONS)
ANSIBLE_DISKS_NFS_PATH ?= $(NFS_PATH)
ANSIBLE_DOCKER_IMAGE_TAG ?= $(DOCKER_IMAGE_TAG)
ANSIBLE_DOCKER_REGISTRY ?= $(DOCKER_REGISTRY)
ANSIBLE_EXTRA_VARS ?= target=localhost
ANSIBLE_GIT_DIRECTORY ?= /src/$(subst git@,,$(subst ssh://,,$(GIT_REPOSITORY)))
ANSIBLE_GIT_KEY_FILE ?= ~$(ANSIBLE_USERNAME)/.ssh/$(notdir $(ANSIBLE_SSH_PRIVATE_KEY))
ANSIBLE_GIT_REPOSITORY ?= $(GIT_REPOSITORY)
ANSIBLE_GIT_VERSION ?= $(BRANCH)
ANSIBLE_INVENTORY ?= ansible/inventories
ANSIBLE_PLAYBOOK ?= ansible/playbook.yml
ANSIBLE_SSH_PRIVATE_KEY ?= ~/.ssh/id_rsa
ANSIBLE_SERVER_NAME ?= $(SERVER_NAME)
ANSIBLE_USERNAME ?= root
ANSIBLE_VERBOSE ?= -v
CMDS += ansible ansible-playbook
ENV_VARS += ANSIBLE_AWS_ACCESS_KEY_ID ANSIBLE_AWS_DEFAULT_OUTPUT ANSIBLE_AWS_DEFAULT_REGION ANSIBLE_AWS_SECRET_ACCESS_KEY ANSIBLE_CONFIG ANSIBLE_DISKS_NFS_DISK ANSIBLE_DISKS_NFS_OPTIONS ANSIBLE_DISKS_NFS_PATH ANSIBLE_DOCKER_IMAGE_TAG ANSIBLE_DOCKER_REGISTRY ANSIBLE_EXTRA_VARS ANSIBLE_GIT_DIRECTORY ANSIBLE_GIT_KEY_FILE ANSIBLE_GIT_REPOSITORY ANSIBLE_GIT_VERSION ANSIBLE_INVENTORY ANSIBLE_PLAYBOOK ANSIBLE_SSH_PRIVATE_KEY ANSIBLE_USERNAME ANSIBLE_VERBOSE
ifeq ($(DEBUG), true)
ANSIBLE_VERBOSE := -vvvv
endif
ifeq ($(DOCKER), true)
define ansible
$(call run,$(DOCKER_SSH_AUTH) -v ~/.aws:/home/$(USER)/.aws --add-host=host.docker.internal:$(DOCKER_INTERNAL_DOCKER_HOST) $(DOCKER_REPOSITORY)/ansible:$(DOCKER_IMAGE_TAG) $(ANSIBLE_ARGS) -i $(ANSIBLE_INVENTORY)/.host.docker.internal $(ANSIBLE_VERBOSE) $(1))
endef
define ansible-playbook
$(call run,$(DOCKER_SSH_AUTH) -v ~/.aws:/home/$(USER)/.aws --add-host=host.docker.internal:$(DOCKER_INTERNAL_DOCKER_HOST) --entrypoint=ansible-playbook $(DOCKER_REPOSITORY)/ansible:$(DOCKER_IMAGE_TAG) $(ANSIBLE_ARGS) -i $(ANSIBLE_INVENTORY)/.host.docker.internal $(ANSIBLE_VERBOSE) $(1))
endef
define ansible-pull
# TODO : run ansible in docker and target localhost outside docker
IFS=$$'\n'; $(ECHO) env $(foreach var,$(ENV_VARS),$(if $($(var)),$(var)='$($(var))')) $(shell printenv |awk -F '=' 'NR == FNR { if($$1 !~ /^(\#|$$)/) { A[$$1]; next } } ($$1 in A)' .env.dist - 2>/dev/null) $$(cat $(ENV_FILE) 2>/dev/null |awk -F "=" '$$1 ~! /^\(#|$$\)/') ansible-pull $(ANSIBLE_ARGS) $(ANSIBLE_VERBOSE) $(1)
endef
else
define ansible
$(call run,ansible $(ANSIBLE_ARGS) $(ANSIBLE_VERBOSE) $(1))
endef
define ansible-playbook
$(call run,ansible-playbook $(ANSIBLE_ARGS) $(ANSIBLE_VERBOSE) $(1))
endef
define ansible-pull
$(call run,ansible-pull $(ANSIBLE_ARGS) $(ANSIBLE_VERBOSE) $(1))
endef
endif
+23
View File
@@ -0,0 +1,23 @@
AWS_ACCESS_KEY_ID ?= $(shell $(call conf,$(HOME)/.aws/credentials,$(or $(AWS_PROFILE),default),aws_access_key_id))
AWS_AMI_DESCRIPTION ?= app: $(APP) branch: $(BRANCH) env: $(ENV) iso: $(AWS_S3_KEY) user: $(USER) version: $(VERSION)
AWS_AMI_NAME ?= $(USER)/$(ENV)/$(APP)/ami/$(VERSION)/$(shell date +%Y%m%dT%H%M%S)
AWS_DEFAULT_REGION ?= eu-west-1
AWS_DEFAULT_OUTPUT ?= text
AWS_INSTANCE_ID ?= $(shell timeout 0.1 curl -s http://169.254.169.254/latest/meta-data/instance-id 2>/dev/null)
AWS_VM_IMPORT_ROLE_NAME ?= vmimport
AWS_S3_BUCKET ?= $(USER)-$(ENV)-config
AWS_S3_KEY ?= $(PACKER_ISO_FILE)
AWS_SECRET_ACCESS_KEY ?= $(shell $(call conf,$(HOME)/.aws/credentials,$(or $(AWS_PROFILE),default),aws_secret_access_key))
AWS_SNAP_DESCRIPTION ?= iso: $(AWS_S3_KEY) env: $(ENV) app: $(APP) branch: $(BRANCH) version: $(VERSION) user: $(USER) etag: $(AWS_S3_KEY_ETAG) date: $(AWS_S3_KEY_DATE)
CMDS += aws
ENV_VARS += AWS_ACCESS_KEY_ID AWS_AMI_DESCRIPTION AWS_AMI_NAME AWS_DEFAULT_OUTPUT AWS_DEFAULT_REGION AWS_INSTANCE_ID AWS_PROFILE AWS_S3_BUCKET AWS_S3_KEY AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN AWS_SNAP_DESCRIPTION AWS_SNAP_ID
ifeq ($(DOCKER), true)
define aws
$(call run,$(DOCKER_SSH_AUTH) -v $$HOME/.aws:/root/.aws:ro anigeo/awscli:latest $(1))
endef
else
define aws
$(call run,aws $(1))
endef
endif
+36
View File
@@ -0,0 +1,36 @@
CMDS += openstack ssh-run terraform
COMPOSE_IGNORE_ORPHANS ?= true
CONTEXT += GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME
DOCKER_BUILD_VARS += SSH_BASTION_HOSTNAME SSH_BASTION_USERNAME SSH_PUBLIC_HOST_KEYS SSH_PRIVATE_IP_RANGE
DOCKER_SERVICE ?= cli
ELASTICSEARCH_HOST ?= elasticsearch
ELASTICSEARCH_PORT ?= 9200
ELASTICSEARCH_PROTOCOL ?= http
ENV_VARS += COMPOSE_IGNORE_ORPHANS DOCKER_IMAGE_CLI DOCKER_IMAGE_SSH DOCKER_NAME_CLI DOCKER_NAME_SSH ELASTICSEARCH_HOST ELASTICSEARCH_PASSWORD ELASTICSEARCH_PORT ELASTICSEARCH_PROTOCOL ELASTICSEARCH_USERNAME GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME SETUP_SYSCTL_CONFIG SSH_BASTION_HOSTNAME SSH_BASTION_USERNAME SSH_PUBLIC_HOST_KEYS SSH_PRIVATE_IP_RANGE
GIT_AUTHOR_EMAIL ?= $(shell git config user.email 2>/dev/null)
GIT_AUTHOR_NAME ?= $(shell git config user.name 2>/dev/null)
HOME ?= /home/$(USER)
NFS_DISK ?= $(NFS_HOST):/$(SHARED)
NFS_OPTIONS ?= rw,rsize=8192,wsize=8192,bg,hard,intr,nfsvers=3,noatime,nodiratime,actimeo=3
NFS_PATH ?= /srv/$(subst :,,$(NFS_DISK))
SETUP_NFSD ?= false
SETUP_NFSD_OSX_CONFIG ?= nfs.server.bonjour=0 nfs.server.mount.regular_files=1 nfs.server.mount.require_resv_port=0 nfs.server.nfsd_threads=16 nfs.server.async=1
SETUP_SYSCTL ?= false
SETUP_SYSCTL_CONFIG ?= vm.max_map_count=262144 vm.overcommit_memory=1 fs.file-max=8388608 net.core.somaxconn=1024
SHELL ?= /bin/sh
SSH_BASTION_HOSTNAME ?=
SSH_BASTION_USERNAME ?=
SSH_PUBLIC_HOST_KEYS ?= $(SSH_REMOTE_HOSTS) $(SSH_BASTION_HOSTNAME)
SSH_PRIVATE_IP_RANGE ?= 10.10.*
SSH_REMOTE_HOSTS ?= github.com gitlab.com
STACK ?= base logs services
define setup-nfsd-osx
$(eval dir:=$(or $(1),$(MONOREPO_DIR)))
$(eval uid:=$(or $(2),$(UID)))
$(eval gid:=$(or $(3),$(GID)))
grep "$(dir)" /etc/exports >/dev/null 2>&1 || echo "$(dir) -alldirs -mapall=$(uid):$(gid) localhost" |sudo tee -a /etc/exports >/dev/null
$(foreach config,$(SETUP_NFSD_OSX_CONFIG),grep "$(config)" /etc/nfs.conf >/dev/null 2>&1 || echo "$(config)" |sudo tee -a /etc/nfs.conf >/dev/null &&) true
nfsd status >/dev/null || sudo nfsd enable
showmount -e localhost |grep "$(dir)" >/dev/null 2>&1 || sudo nfsd restart
endef
+17
View File
@@ -0,0 +1,17 @@
ENV_VARS += OS_AUTH_URL OS_TENANT_ID OS_TENANT_NAME OS_USERNAME OS_PASSWORD OS_REGION_NAME OS_USER_DOMAIN_NAME OS_PROJECT_DOMAIN_NAME
ifeq ($(DEBUG), true)
OPENSTACK_ARGS += --debug
endif
ifeq ($(ENV), local)
OPENSTACK_ARGS += -v
endif
ifeq ($(DOCKER), true)
define openstack
$(call run,$(DOCKER_SSH_AUTH) $(DOCKER_REPOSITORY)/openstack:$(DOCKER_IMAGE_TAG) $(1))
endef
else
define openstack
$(call run,openstack $(1))
endef
endif
+6
View File
@@ -0,0 +1,6 @@
PACKER_ALPINE_ARCH ?= x86_64
PACKER_ALPINE_RELEASE ?= 3.12.0
PACKER_BUILD_VARS += alpine_arch alpine_release alpine_version
alpine_arch ?= $(PACKER_ALPINE_ARCH)
alpine_release ?= $(PACKER_ALPINE_RELEASE)
alpine_version ?= $(subst $(eval) ,.,$(wordlist 1, 2, $(subst ., ,$(alpine_release))))
+4
View File
@@ -0,0 +1,4 @@
PACKER_BUILD_VARS += ansible_extra_vars ansible_user ansible_verbose
ansible_extra_vars ?= $(patsubst target=%,target=default,$(ANSIBLE_EXTRA_VARS))
ansible_user ?= $(ANSIBLE_USERNAME)
ansible_verbose ?= $(ANSIBLE_VERBOSE)
+126
View File
@@ -0,0 +1,126 @@
CMDS += packer
ENV_VARS += PACKER_CACHE_DIR PACKER_KEY_INTERVAL PACKER_LOG
KVM_GID ?= $(call getent-group,kvm)
PACKER_ARCH ?= $(PACKER_ALPINE_ARCH)
PACKER_BOOT_WAIT ?= 11s
PACKER_BUILD_ARGS ?= -on-error=cleanup $(foreach var,$(PACKER_BUILD_VARS),$(if $($(var)),-var $(var)='$($(var))'))
PACKER_BUILD_VARS += accelerator boot_wait hostname iso_name iso_size output password qemuargs ssh_wait_timeout template username
PACKER_CACHE_DIR ?= build/cache
PACKER_HOSTNAME ?= $(PACKER_TEMPLATE)
PACKER_ISO_DATE ?= $(shell stat -c %y $(PACKER_ISO_FILE) 2>/dev/null)
PACKER_ISO_FILES ?= $(wildcard build/iso/*/*/*.iso)
PACKER_ISO_FILE = $(PACKER_OUTPUT)/$(PACKER_ISO_NAME).iso
PACKER_ISO_INFO = $(PACKER_OUTPUT)/$(PACKER_ISO_NAME).nfo
PACKER_ISO_NAME = $(PACKER_TEMPLATE)-$(PACKER_RELEASE)-$(PACKER_ARCH)
PACKER_ISO_SIZE ?= 1024
PACKER_KEY_INTERVAL ?= 10ms
PACKER_LOG ?= 1
PACKER_OUTPUT ?= build/iso/$(ENV)/$(PACKER_TEMPLATE)/$(PACKER_RELEASE)-$(PACKER_ARCH)
PACKER_PASSWORD ?= $(PACKER_TEMPLATE)
PACKER_QEMU_ACCELERATOR ?= kvm
PACKER_QEMU_ARCH ?= $(PACKER_ARCH)
PACKER_QEMU_ARGS ?= -machine type=pc,accel=$(PACKER_QEMU_ACCELERATOR) -device virtio-rng-pci,rng=rng0,bus=pci.0,addr=0x7 -object rng-random,filename=/dev/urandom,id=rng0
PACKER_RELEASE ?= $(PACKER_ALPINE_RELEASE)
PACKER_SSH_ADDRESS ?= $(if $(ssh_bind_address),$(ssh_bind_address),0.0.0.0)
PACKER_SSH_PORT ?= $(if $(ssh_port_max),$(ssh_port_max),2222)
PACKER_SSH_WAIT_TIMEOUT ?= 42s
PACKER_TEMPLATES ?= $(wildcard packer/*/*.json)
PACKER_TEMPLATE ?= alpine
PACKER_USERNAME ?= root
PACKER_VNC_PORT ?= $(if $(vnc_port_max),$(vnc_port_max),5900)
PACKER_VNC_ADDRESS ?= $(if $(vnc_bind_address),$(vnc_bind_address),0.0.0.0)
ifeq ($(DEBUG), true)
PACKER_BUILD_ARGS += -debug
endif
ifeq ($(FORCE), true)
PACKER_BUILD_ARGS += -force
endif
ifeq ($(ENV), local)
PACKER_BUILD_ARGS += -var ssh_port_max=$(PACKER_SSH_PORT) -var vnc_port_max=$(PACKER_VNC_PORT) -var vnc_bind_address=$(PACKER_VNC_ADDRESS)
endif
accelerator ?= $(PACKER_QEMU_ACCELERATOR)
boot_wait ?= $(PACKER_BOOT_WAIT)
hostname ?= $(PACKER_HOSTNAME)
iso_name ?= $(PACKER_ISO_NAME)
iso_size ?= $(PACKER_ISO_SIZE)
output ?= $(PACKER_OUTPUT)
password ?= $(PACKER_PASSWORD)
qemuargs ?= $(call arrays_of_dquoted_args, $(PACKER_QEMU_ARGS))
ssh_wait_timeout ?= $(PACKER_SSH_WAIT_TIMEOUT)
template ?= $(PACKER_TEMPLATE)
username ?= $(PACKER_USERNAME)
ifneq ($(filter $(ENV),$(ENV_DEPLOY)),)
ifeq ($(password), $(template))
password := $(or $(shell pwgen -csy -r\' 64 1 2>/dev/null),$(shell date +%s | shasum -a 256 2>/dev/null | base64 | head -c 64))
endif
endif
ifeq ($(HOST_SYSTEM),DARWIN)
ifneq ($(DOCKER), true)
PACKER_QEMU_ACCELERATOR := hvf
else
PACKER_QEMU_ACCELERATOR := tcg
PACKER_QEMU_ARGS += -cpu max,vendor=GenuineIntel,vmware-cpuid-freq=on,+invtsc,+aes,+vmx
endif
else ifeq ($(HOST_SYSTEM),LINUX)
DOCKER_RUN_OPTIONS_PACKER := $(if $(KVM_GID),--group-add $(KVM_GID)) --device /dev/kvm
else ifeq ($(HOST_SYSTEM),WINDOWS)
PACKER_QEMU_ACCELERATOR := hax
endif
ifeq ($(DOCKER), true)
# packer ansible provisionner needs:
## empty local ssh agent (ssh-add -D)
## ANSIBLE_SSH_PRIVATE_KEY set to a key giving access to ANSIBLE_GIT_REPOSITORY without password
## ANSIBLE_AWS_ACCESS_KEY_ID and ANSIBLE_AWS_SECRET_ACCESS_KEY
define packer
$(call run,$(DOCKER_RUN_OPTIONS_PACKER) $(DOCKER_SSH_AUTH) -p $(PACKER_SSH_PORT):$(PACKER_SSH_PORT) -p $(PACKER_VNC_PORT):$(PACKER_VNC_PORT) $(DOCKER_REPOSITORY)/packer:$(DOCKER_IMAGE_TAG) $(1))
endef
define packer-qemu
echo Running $(1)
$(call run,$(DOCKER_RUN_OPTIONS_PACKER) -p $(PACKER_SSH_PORT):$(PACKER_SSH_PORT) -p $(PACKER_VNC_PORT):$(PACKER_VNC_PORT) --entrypoint=qemu-system-$(PACKER_QEMU_ARCH) $(DOCKER_REPOSITORY)/packer:$(DOCKER_IMAGE_TAG) $(PACKER_QEMU_ARGS) -m 512m -drive file=$(1)$(comma)format=raw -net nic$(comma)model=virtio -net user$(comma)hostfwd=tcp:$(PACKER_SSH_ADDRESS):$(PACKER_SSH_PORT)-:22 -vnc $(PACKER_VNC_ADDRESS):$(subst 590,,$(PACKER_VNC_PORT)))
endef
else
define packer
$(call run,packer $(1))
endef
define packer-qemu
echo Running $(1)
$(call run,qemu-system-$(PACKER_QEMU_ARCH) $(PACKER_QEMU_ARGS) -m 512m -drive file=$(1)$(comma)format=raw -net nic$(comma)model=virtio -net user$(comma)hostfwd=tcp:$(PACKER_SSH_ADDRESS):$(PACKER_SSH_PORT)-:22 -vnc $(PACKER_VNC_ADDRESS):$(subst 590,,$(PACKER_VNC_PORT)))
endef
endif
define packer-build
$(eval PACKER_TEMPLATE := $(notdir $(basename $(1))))
echo Building $(PACKER_ISO_FILE)
$(call packer,build $(PACKER_BUILD_ARGS) $(1))
echo 'aws_id: $(ANSIBLE_AWS_ACCESS_KEY_ID)' > $(PACKER_ISO_INFO)
echo 'aws_key: $(ANSIBLE_AWS_SECRET_ACCESS_KEY)' >> $(PACKER_ISO_INFO)
echo 'aws_region: $(ANSIBLE_AWS_DEFAULT_REGION)' >> $(PACKER_ISO_INFO)
echo 'docker_image_tag: $(ANSIBLE_DOCKER_IMAGE_TAG)' >> $(PACKER_ISO_INFO)
echo 'docker_registry: $(ANSIBLE_DOCKER_REGISTRY)' >> $(PACKER_ISO_INFO)
echo 'env: $(ENV)' >> $(PACKER_ISO_INFO)
echo 'file: $(PACKER_ISO_FILE)' >> $(PACKER_ISO_INFO)
echo 'git_branch: $(ANSIBLE_GIT_VERSION)' >> $(PACKER_ISO_INFO)
echo 'git_repository: $(ANSIBLE_GIT_REPOSITORY)' >> $(PACKER_ISO_INFO)
echo 'git_version: $(VERSION)' >> $(PACKER_ISO_INFO)
echo 'host: $(hostname)' >> $(PACKER_ISO_INFO)
echo 'link: s3://$(AWS_S3_BUCKET)/$(AWS_S3_KEY)' >> $(PACKER_ISO_INFO)
echo 'name: $(iso_name)' >> $(PACKER_ISO_INFO)
echo 'nfs_disk: $(ANSIBLE_DISKS_NFS_DISK)' >> $(PACKER_ISO_INFO)
echo 'nfs_path: $(ANSIBLE_DISKS_NFS_PATH)' >> $(PACKER_ISO_INFO)
echo 'pass: $(password)' >> $(PACKER_ISO_INFO)
echo 'size: $(iso_size)' >> $(PACKER_ISO_INFO)
echo 'ssh_key: $(ANSIBLE_SSH_PRIVATE_KEY)' >> $(PACKER_ISO_INFO)
echo 'user: $(username)' >> $(PACKER_ISO_INFO)
endef
define arrays_of_dquoted_args
[ $(subst $(dquote) $(dquote),$(dquote)$(comma) $(dquote),$(subst $(dquote) $(dquote)-,$(dquote) ]$(comma) [ $(dquote)-,$(patsubst %,$(dquote)%$(dquote),$1))) ]
endef
+14
View File
@@ -0,0 +1,14 @@
define ssh-connect
$(eval hosts := $(1))
$(eval command := $(2))
$(eval user := $(or $(3),root))
$(eval DOCKER_EXEC_OPTIONS := -it)
$(foreach host,$(hosts),$(call exec,ssh -t -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no $(user)@$(host) "$(command)") ||) true
endef
define ssh-exec
$(eval hosts := $(1))
$(eval command := $(2))
$(eval user := $(or $(3),root))
$(foreach host,$(hosts),$(call exec,ssh -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no $(user)@$(host) "$(command)") &&) true
endef
+21
View File
@@ -0,0 +1,21 @@
CMDS += terraform
ifeq ($(DOCKER), true)
# packer ansible provisionner needs:
## empty local ssh agent (ssh-add -D)
## ANSIBLE_SSH_PRIVATE_KEY set to a key giving access to ANSIBLE_GIT_REPOSITORY without password
## ANSIBLE_AWS_ACCESS_KEY_ID and ANSIBLE_AWS_SECRET_ACCESS_KEY
define terraform
$(call run,hashicorp/terraform:light $(1))
endef
else
define terraform
$(call run,terraform $(1))
endef
endif
+12
View File
@@ -0,0 +1,12 @@
##
# INFRA
.PHONY: setup-sysctl
setup-sysctl:
ifeq ($(SETUP_SYSCTL),true)
$(call docker-run,--privileged alpine:latest,/bin/sh -c 'echo never > /sys/kernel/mm/transparent_hugepage/enabled ||:' >/dev/null)
$(foreach config,$(SETUP_SYSCTL_CONFIG),$(call docker-run,--privileged alpine:latest,sysctl -q -w $(config)) &&) true
endif
.PHONY: start-up
start-up: base-ssh-add
+7
View File
@@ -0,0 +1,7 @@
.PHONY: openstack
openstack: docker-build-openstack
$(call openstack,$(ARGS))
.PHONY: openstack-image-create
openstack-image-create: $(PACKER_ISO_FILE) docker-build-openstack
$(call openstack,$(OPENSTACK_ARGS) image create --disk-format raw --container-format bare --file $(PACKER_ISO_FILE) "$(PACKER_ISO_NAME)")
+36
View File
@@ -0,0 +1,36 @@
.PHONY: packer
packer:
$(call packer,$(ARGS))
$(PACKER_ISO_FILE):
$(eval FORCE := true)
$(call make,packer-build,,FORCE)
.PHONY: packer-build
packer-build: packer-build-$(PACKER_TEMPLATE) ## Build default packer template
.PHONY: packer-build-templates
packer-build-templates: $(PACKER_TEMPLATES) ## Build all packer templates
.PHONY: $(PACKER_TEMPLATES)
ifeq ($(HOST_SYSTEM),DARWIN)
$(PACKER_TEMPLATES): DOCKER ?= false
endif
$(PACKER_TEMPLATES):
$(call packer-build,$@)
.PHONY: packer-build-%
packer-build-%: docker-build-packer
$(if $(wildcard packer/*/$*.json),\
$(call packer-build,$(wildcard packer/*/$*.json)))
.PHONY: packer-qemu
packer-qemu: packer-qemu-$(PACKER_ISO_NAME) ## Launch iso image in qemu
.PHONY: packer-qemu-%
ifeq ($(HOST_SYSTEM),DARWIN)
packer-qemu-%: DOCKER ?= false
endif
packer-qemu-%: docker-build-packer ## Run iso image in qemu
$(if $(wildcard $(PACKER_OUTPUT)/$*.iso),\
$(call packer-qemu,$(wildcard $(PACKER_OUTPUT)/$*.iso)))
+18
View File
@@ -0,0 +1,18 @@
##
# SSH
.PHONY: ssh
ssh: aws-ec2-get-PrivateIpAddress-$(SERVER_NAME)
$(call ssh-connect,$(AWS_INSTANCE_IP),$(SHELL))
.PHONY: ssh-connect
ssh-connect: aws-ec2-get-PrivateIpAddress-$(SERVER_NAME)
$(call ssh-connect,$(AWS_INSTANCE_IP),make connect $(if $(SERVICE),SERVICE=$(SERVICE)))
.PHONY: ssh-exec
ssh-exec: aws-ec2-get-PrivateIpAddress-$(SERVER_NAME)
$(call ssh-exec,$(AWS_INSTANCE_IP),make exec $(if $(SERVICE),SERVICE=$(SERVICE)) $(if $(ARGS),ARGS='\''"$(ARGS)"'\''))
.PHONY: ssh-run
ssh-run: aws-ec2-get-PrivateIpAddress-$(SERVER_NAME)
$(call ssh-exec,$(AWS_INSTANCE_IP),make run $(if $(SERVICE),SERVICE=$(SERVICE)) $(if $(ARGS),ARGS='\''"$(ARGS)"'\''))
+4
View File
@@ -0,0 +1,4 @@
.PHONY: terraform
terraform:
$(call terraform,$(ARGS))
+29
View File
@@ -0,0 +1,29 @@
##
# INSTALL
.PHONY: install app-install
install: app-install ## Install application
.PHONY: install-mysql-database-%
install-mysql-database-%: infra-base
$(call exec,mysql -h mysql -u root -proot $* -e "use $*" >/dev/null 2>&1 || mysql -h mysql -u root -proot mysql -e "create database $* character set utf8 collate utf8_unicode_ci;")
$(call exec,mysql -h mysql -u $* -p$* $* -e "use $*" >/dev/null 2>&1 || mysql -h mysql -u root -proot mysql -e "grant all privileges on $*.* to '\''$*'\''@'\''%'\'' identified by '\''$*'\''; flush privileges;")
$(call exec,[ $$(mysql -h mysql -u $* -p$* $* -e "show tables" 2>/dev/null |wc -l) -eq 0 ] && [ -f "${APP_DIR}/$*.mysql.gz" ] && gzip -cd "${APP_DIR}/$*.mysql.gz" |mysql -h mysql -u root -proot $* || true)
.PHONY: install-pgsql-database-%
install-pgsql-database-%: infra-base
$(call exec,PGPASSWORD=$* psql -h postgres -U $* template1 -c "\q" >/dev/null 2>&1 || PGPASSWORD=postgres psql -h postgres -U postgres -c "create user $* with createdb password '\''$*'\'';")
$(call exec,PGPASSWORD=$* psql -h postgres -U $* -d $* -c "" >/dev/null 2>&1 || PGPASSWORD=postgres psql -h postgres -U postgres -c "create database $* owner $* ;")
$(call exec,[ $$(PGPASSWORD=$* psql -h postgres -U $* -d $* -c "\d" 2>/dev/null |wc -l) -eq 0 ] && [ -f "${APP_DIR}/$*.pgsql.gz" ] && gzip -cd "${APP_DIR}/$*.pgsql.gz" |PGPASSWORD="postgres" psql -h postgres -U postgres -d $* || true)
$(call exec,[ $$(PGPASSWORD=$* psql -h postgres -U $* -d $* -c "\d" 2>/dev/null |wc -l) -eq 0 ] && [ -f "${APP_DIR}/$*.pgsql" ] && PGPASSWORD="postgres" psql -h postgres -U postgres -c "ALTER ROLE $* WITH SUPERUSER" && PGPASSWORD="postgres" pg_restore -h postgres --no-owner --role=$* -U postgres -d $* ${APP_DIR}/$*.pgsql && PGPASSWORD="postgres" psql -h postgres -U postgres -c "ALTER ROLE $* WITH NOSUPERUSER" || true)
.PHONY: install-infra
install-infra: infra-install
.PHONY: install-parameters
install-parameters:
$(call install-parameters)
.PHONY: install-parameters-%
install-parameters-%:
$(call install-parameters,$*)
+9
View File
@@ -0,0 +1,9 @@
##
# CLEAN
.PHONY: clean-js-app
clean-js-app: clean-js-assets-deps
.PHONY: clean-js-assets-deps
clean-js-assets-deps: bootstrap
$(call docker-compose-exec,$(DOCKER_SERVICE),rm -Rf node_modules/*)
+21
View File
@@ -0,0 +1,21 @@
##
# DEV
## Build assets
.PHONY: dev-assets
dev-assets: ## Build assets
$(call docker-compose-exec,$(DOCKER_SERVICE),yarn build:dev:watch)
.PHONY: dev-outdated
dev-outdated:
$(call docker-compose-exec,$(DOCKER_SERVICE),yarn outdated)
# compile webpack assets (REACT)
.PHONY: dev-webpack-compile
dev-webpack-compile: bootstrap ## Compile dev assets
$(call docker-compose-exec,$(DOCKER_SERVICE),yarn encore dev)
# watch webpack assets updates (REACT)
.PHONY: dev-webpack-watch
dev-webpack-watch: bootstrap ## Watch dev assets update
$(call docker-compose-exec,$(DOCKER_SERVICE),yarn encore dev --watch)
+22
View File
@@ -0,0 +1,22 @@
##
# INSTALL
.PHONY: install-bower
install-bower: bootstrap
$(call docker-compose-exec,$(DOCKER_SERVICE),npm install bower --allow-root)
$(call docker-compose-exec,$(DOCKER_SERVICE),./node_modules/bower/bin/bower install --allow-root)
.PHONY: install-npm
install-npm: bootstrap
$(call docker-compose-exec,$(DOCKER_SERVICE),npm install)
.PHONY: install-npm-run-build
install-npm-run-build: install-npm-run-build-$(SYMFONY_ENV)
.PHONY: install-npm-run-build-%
install-npm-run-build-%: bootstrap
$(call docker-compose-exec,$(DOCKER_SERVICE),npm run build:$*)
.PHONY: install-yarn
install-yarn: bootstrap
$(call docker-compose-exec,$(DOCKER_SERVICE),yarn install)
+17
View File
@@ -0,0 +1,17 @@
##
# TEST
.PHONY: test-assets
test-assets: bootstrap
$(call docker-compose-exec,$(DOCKER_SERVICE),yarn test)
## Run functional tests (make test-func TEST="S01-U1-find-product")
.PHONY: test-func-js
test-func-js: bootstrap ## Run functional tests (js)
ifdef TEST
$(call docker-compose-exec,$(DOCKER_SERVICE),yarn test:func -- --test tests/Functional/specs/$(TEST).js --env $(TESTENV))
else ifdef TESTSUITE
$(call docker-compose-exec,$(DOCKER_SERVICE),yarn test:func -- --tag $(TESTSUITE) --env $(TESTENV))
else
$(call docker-compose-exec,$(DOCKER_SERVICE),yarn test:func -- --env $(TESTENV))
endif
+6
View File
@@ -0,0 +1,6 @@
##
# UPDATE
.PHONY: update-npm
update-npm: bootstrap
$(call docker-compose-exec,$(DOCKER_SERVICE),npm upgrade)
+23
View File
@@ -0,0 +1,23 @@
##
# CACHE
## Clear symfony cache
.PHONY: cache-clear
cache-clear: cache-clear-dev cache-clear-prod
.PHONY: cache-clear-%
cache-clear-%: bootstrap ## Clear symfony cache
$(call docker-compose-exec,$(DOCKER_SERVICE),app/console cache:clear --env=$*)
.PHONY: cache-rm
cache-rm: bootstrap
$(call docker-compose-exec,$(DOCKER_SERVICE),rm -Rf app/cache/* app/logs/*)
$(if $(filter $(ENV),$(ENV_DEPLOY)),$(call docker-compose-exec,$(DOCKER_SERVICE),chown www-data app/cache/ app/logs/))
.PHONY: cache-warmup
cache-warmup: cache-warmup-$(SYMFONY_ENV)
$(if $(filter $(ENV),$(ENV_DEPLOY)),$(call docker-compose-exec,$(DOCKER_SERVICE),chown -R www-data app/cache/ app/logs/))
.PHONY: cache-warmup-%
cache-warmup-%: bootstrap
$(call docker-compose-exec,$(DOCKER_SERVICE),app/console cache:warmup --env=$*)
+12
View File
@@ -0,0 +1,12 @@
##
# CLEAN
.PHONY: clean-php-app
clean-php-app: bootstrap
$(call docker-compose-exec,$(DOCKER_SERVICE),rm -rf app/bootstrap.php.cache)
$(call docker-compose-exec,$(DOCKER_SERVICE),rm -rf app/cache/* app/cach~)
$(call docker-compose-exec,$(DOCKER_SERVICE),rm -rf app/logs/*)
$(call docker-compose-exec,$(DOCKER_SERVICE),rm -rf var/cache/* var/cach~)
$(call docker-compose-exec,$(DOCKER_SERVICE),rm -rf var/logs/*)
$(call docker-compose-exec,$(DOCKER_SERVICE),rm -rf vendor/*)
$(call docker-compose-exec,$(DOCKER_SERVICE),rm -rf node_modules/*)
+24
View File
@@ -0,0 +1,24 @@
COMPOSER_ARGS ?= --optimize-autoloader
COMPOSER_MEMORY_LIMIT ?= -1
CONTEXT += COMPOSER_ARGS
ifeq ($(SYMFONY_ENV), prod)
COMPOSER_ARGS += --classmap-authoritative --prefer-dist --no-dev --no-interaction
endif
ifeq ($(DRONE), true)
COMPOSER_ARGS += --no-progress
endif
define composer
$(call docker-compose-exec,$(DOCKER_SERVICE),COMPOSER_MEMORY_LIMIT=$(COMPOSER_MEMORY_LIMIT) SYMFONY_ENV=$(SYMFONY_ENV) composer $(1) $(COMPOSER_ARGS))
endef
define composer-require-vendor-binary
$(eval vendor:=$(1))
$(eval binary:=$(or $(2),$(lastword $(subst /, ,$(vendor)))))
$(eval version:=$(or $(addprefix :,$(3)),$(shell awk '/'$(subst /,\\/,$(vendor))'/ {gsub("[\",]","",$$2); print ":"$$2}' composer.json 2>/dev/null)))
$(eval DRYRUN_IGNORE := true)
$(eval COMPOSER_REQUIRE := $(shell $(call docker-compose-exec,$(DOCKER_SERVICE),[ -f vendor/$(vendor)/$(binary) ] || echo true)))
$(eval DRYRUN_IGNORE := false)
$(if $(COMPOSER_REQUIRE),$(call docker-compose-exec,$(DOCKER_SERVICE),mkdir -p vendor/$(vendor) && cd /tmp && COMPOSER_MEMORY_LIMIT=$(COMPOSER_MEMORY_LIMIT) SYMFONY_ENV=$(SYMFONY_ENV) composer require "$(vendor)$(version)" --prefer-source --no-interaction --dev && cd - && ln -s /tmp/vendor/$(vendor)/$(binary) vendor/$(vendor)/$(binary)))
endef
+8
View File
@@ -0,0 +1,8 @@
BUILD_APP_VARS += SYMFONY_ENV
DOCKER_SERVICE ?= php
ifneq (,$(filter $(ENV),$(ENV_DEPLOY)))
SYMFONY_ENV ?= prod
else
SYMFONY_ENV ?= dev
endif
+10
View File
@@ -0,0 +1,10 @@
##
# DEV
.PHONY: dev-phpcs
dev-phpcs: bootstrap install-phpcs
$(call docker-compose-exec,$(DOCKER_SERVICE),bin/phpcs --standard=PSR2 --colors -p ./src)
.PHONY: dev-phpcbf
dev-phpcbf: bootstrap install-phpcbf
$(call docker-compose-exec,$(DOCKER_SERVICE),bin/phpcbf ./src/ --ignore=*.js)
+43
View File
@@ -0,0 +1,43 @@
##
# INSTALL
.PHONY: install-assets
install-assets: install-assets-$(SYMFONY_ENV)
.PHONY: install-assets-%
install-assets-%: bootstrap
$(call docker-compose-exec,$(DOCKER_SERVICE),app/console assetic:dump --env=$*)
$(call docker-compose-exec,$(DOCKER_SERVICE),app/console assets:install --env=$*)
$(if $(filter $(ENV),$(ENV_DEPLOY)),$(call docker-compose-exec,$(DOCKER_SERVICE),chown -R www-data web/bundles/ web/css/ web/js/))
.PHONY: install-codecept
install-codecept: bootstrap install-phpunit vendor/codeception/codeception/codecept
vendor/codeception/codeception/codecept:
$(call composer-require-vendor-binary,codeception/codeception,codecept)
.PHONY: install-composer
install-composer: bootstrap
$(call composer,install)
.PHONY: install-doctrine-schema-update
install-doctrine-schema-update: bootstrap
$(call docker-compose-exec,$(DOCKER_SERVICE),php app/console doctrine:schema:update --force)
.PHONY: install-phpcbf
install-phpcbf: bootstrap vendor/squizlabs/php_codesniffer/bin/phpcbf
vendor/squizlabs/php_codesniffer/bin/phpcbf:
$(call composer-require-vendor-binary,squizlabs/php_codesniffer,bin/phpcbf)
.PHONY: install-phpcs
install-phpcs: bootstrap vendor/squizlabs/php_codesniffer/bin/phpcs
vendor/squizlabs/php_codesniffer/bin/phpcs:
$(call composer-require-vendor-binary,squizlabs/php_codesniffer,bin/phpcs)
.PHONY: install-phpunit
install-phpunit: bootstrap vendor/phpunit/phpunit/phpunit
vendor/phpunit/phpunit/phpunit:
$(call composer-require-vendor-binary,phpunit/phpunit)
+52
View File
@@ -0,0 +1,52 @@
##
# TEST
## Run unit tests
.PHONY: test
test: test-unit ## Run unit tests
## Run codeception tests
.PHONY: test-codeception-%
test-codeception-%: bootstrap install-codecept ## Run codeception tests
$(call docker-compose-exec,$(DOCKER_SERVICE),bin/codecept run $*)
## Run old unit tests with code coverage
.PHONY: test-coverage
test-coverage: bootstrap install-phpunit ## Run code coverage
$(call docker-compose-exec,$(DOCKER_SERVICE),bin/phpunit --testsuite unit --coverage-text)
## Run codeception tests with coverage
.PHONY: test-coverage-codeception-%
test-coverage-codeception-%: bootstrap install-codecept ## Run codeception tests with coverage
$(call docker-compose-exec,$(DOCKER_SERVICE),bin/codecept run $* --coverage --coverage-html)
## Run phpunit functional tests
.PHONY: test-func
test-func: bootstrap install-phpunit ## Run functional tests
$(call docker-compose-exec,$(DOCKER_SERVICE),bin/phpunit --testsuite functional)
## Loop unit tests
.PHONY: test-loop
test-loop: bootstrap install-phpunit ## Loop unit tests
while true; \
do $(MAKE) test; \
read continue; \
done;
## Run search tests
.PHONY: test-search
test-search: bootstrap install-phpunit ## Run search tests
$(call docker-compose-exec,$(DOCKER_SERVICE),bin/phpunit --testsuite search)
.PHONY: test-templates
test-templates: bootstrap
$(call docker-compose-exec,$(DOCKER_SERVICE),php app/console lint:twig @UIBundle)
## Run old unit tests
.PHONY: test-unit
test-unit: bootstrap install-phpunit ## Run unit tests
ifdef FILTER
$(call docker-compose-exec,$(DOCKER_SERVICE),bin/phpunit --testsuite unit --filter $(FILTER))
else
$(call docker-compose-exec,$(DOCKER_SERVICE),bin/phpunit --testsuite unit)
endif
+6
View File
@@ -0,0 +1,6 @@
##
# UPDATE
.PHONY: update-database
update-database: bootstrap
$(call docker-compose-exec,$(DOCKER_SERVICE),app/console --no-interaction doctrine:migration:migrate)
+75
View File
@@ -0,0 +1,75 @@
COMPOSE_VERSION ?= 1.24.1
COMPOSE_PROJECT_NAME_INFRA ?= $(USER)_$(ENV)_infra
COMPOSE_PROJECT_NAME_INFRA_NODE ?= node_infra
DOCKER_EXEC_OPTIONS ?=
DOCKER_IMAGE ?= $(DOCKER_IMAGE_CLI)
DOCKER_IMAGE_CLI ?= $(DOCKER_REPOSITORY_INFRA)/cli
DOCKER_IMAGE_SSH ?= $(DOCKER_REPOSITORY_INFRA)/ssh
DOCKER_NAME ?= $(DOCKER_NAME_CLI)
DOCKER_NAME_CLI ?= $(COMPOSE_PROJECT_NAME_INFRA)_cli
DOCKER_NAME_SSH ?= $(COMPOSE_PROJECT_NAME_INFRA)_ssh
DOCKER_NETWORK ?= $(DOCKER_NETWORK_PRIVATE)
DOCKER_NETWORK_PRIVATE ?= $(ENV)
DOCKER_NETWORK_PUBLIC ?= node
DOCKER_REPOSITORY_INFRA ?= $(subst _,/,$(COMPOSE_PROJECT_NAME_INFRA))
DOCKER_REPOSITORY_INFRA_NODE ?= $(subst _,/,$(COMPOSE_PROJECT_NAME_INFRA_NODE))
# DOCKER_RUN_OPTIONS: default options to `docker run` command
DOCKER_RUN_OPTIONS ?= --rm -it
# DOCKER_RUN_VOLUME: options to `docker run` command to mount additionnal volumes
DOCKER_RUN_VOLUME ?= -v $$PWD:$$PWD
DOCKER_RUN_WORKDIR ?= -w $$PWD
DOCKER_VOLUME_SSH ?= $(COMPOSE_PROJECT_NAME_INFRA)_ssh
ENV_VARS += DOCKER_NETWORK_PRIVATE DOCKER_NETWORK_PUBLIC DOCKER_REPOSITORY_INFRA DOCKER_REPOSITORY_INFRA_NODE DOCKER_VOLUME_SSH
ifeq ($(DRONE), true)
DOCKER_RUN_OPTIONS := --rm --network $(DOCKER_NETWORK)
# When running docker command in drone, we are already in a docker (dind).
# Whe need to find the volume mounted in the current docker (runned by drone) to mount it in our docker command.
# If we do not mount the volume in our docker, we wont be able to access the files in this volume as the /drone/src directory would be empty.
DOCKER_RUN_VOLUME := -v /var/run/docker.sock:/var/run/docker.sock -v $$(docker inspect $$(basename $$(cat /proc/1/cpuset)) 2>/dev/null |awk 'BEGIN {FS=":"} $$0 ~ /"drone-[a-zA-Z0-9]*:\/drone"$$/ {gsub(/^[ \t\r\n]*"/,"",$$1); print $$1; exit}'):/drone $(if $(wildcard /root/.netrc),-v /root/.netrc:/root/.netrc)
else
DOCKER_RUN_VOLUME := -v /var/run/docker.sock:/var/run/docker.sock -v $(or $(MONOREPO_DIR),$(APP_DIR)):$(or $(WORKSPACE_DIR),$(MONOREPO_DIR),$(APP_DIR))
endif
ifeq ($(DOCKER), true)
DOCKER_SSH_AUTH := -e SSH_AUTH_SOCK=/tmp/ssh-agent/socket -v $(DOCKER_VOLUME_SSH):/tmp/ssh-agent
define docker-run
$(call run,$(or $(1),$(DOCKER_IMAGE):$(DOCKER_IMAGE_TAG)) $(2))
endef
ifeq ($(DRONE), true)
define exec
$(call run,$(DOCKER_SSH_AUTH) $(DOCKER_IMAGE) sh -c '$(or $(1),$(SHELL))')
endef
else
define exec
$(ECHO) docker exec $(ENV_ARGS) $(DOCKER_EXEC_OPTIONS) $(DOCKER_RUN_WORKDIR) $(DOCKER_NAME) sh -c '$(or $(1),$(SHELL))'
endef
endif
define run
$(ECHO) docker run $(DOCKER_RUN_OPTIONS) $(patsubst %,--env-file %,$(ENV_FILE)) $(ENV_ARGS) $(DOCKER_RUN_VOLUME) $(DOCKER_RUN_WORKDIR) $(1)
endef
else
SHELL := /bin/bash
define docker-run
$(ECHO) docker run $(DOCKER_RUN_OPTIONS) $(patsubst %,--env-file %,$(ENV_FILE)) $(foreach var,$(ENV_VARS),$(if $($(var)),-e $(var)='$($(var))')) $(shell printenv |awk -F '=' 'NR == FNR { if($$1 !~ /^(\#|$$)/) { A[$$1]; next } } ($$1 in A) {print "-e "$$0}' .env.dist - 2>/dev/null) $(DOCKER_RUN_VOLUME) $(DOCKER_RUN_WORKDIR) $(or $(1),$(DOCKER_IMAGE):$(DOCKER_IMAGE_TAG)) $(2)
endef
define exec
$(call run,sh -c '$(or $(1),$(SHELL))')
endef
define run
IFS=$$'\n'; $(ECHO) env $(ENV_ARGS) $$(cat $(ENV_FILE) 2>/dev/null |awk -F "=" '$$1 ~! /^\(#|$$\)/') $(1)
endef
endif
define docker-volume-copy
$(eval from := $(1))
$(eval to := $(2))
$(ECHO) docker volume inspect $(from) >/dev/null
$(ECHO) docker volume inspect $(to) >/dev/null 2>&1 || $(ECHO) docker volume create $(to) >/dev/null
$(ECHO) docker run --rm -v $(from):/from -v $(to):/to alpine ash -c "cd /from; cp -a . /to"
endef
+198
View File
@@ -0,0 +1,198 @@
comma ?= ,
dollar ?= $
dquote ?= "
quote ?= '
APP ?= $(if $(wildcard .git),$(if $(wildcard */.gitrepo),,$(notdir $(CURDIR))),$(notdir $(CURDIR)))
APP_DIR ?= $(if $(APP),$(CURDIR))
BRANCH ?= $(shell git rev-parse --abbrev-ref HEAD)
CMDS ?= exec exec:% exec@% run run:% run@%
COMMIT ?= $(shell git rev-parse $(BRANCH) 2>/dev/null)
CONTEXT ?= $(shell awk 'BEGIN {FS="="}; $$1 !~ /^(\#|$$)/ {print $$1}' .env.dist 2>/dev/null) BRANCH ENV_FILE UID USER VERSION
DEBUG ?= false
DOCKER ?= true
DRONE ?= false
DRYRUN ?= false
DRYRUN_IGNORE ?= false
DRYRUN_RECURSIVE ?= false
ENV ?= local
ENV_DEPLOY ?= preprod prod
ENV_FILE ?= $(wildcard ../$(PARAMETERS)/$(ENV)/$(APP)/.env) .env
ENV_LIST ?= local dev tests preprod prod
ENV_RESET ?= false
ENV_VARS ?= APP APP_DIR BRANCH ENV HOSTNAME GID MONOREPO MONOREPO_DIR TAG UID USER VERSION
GID ?= $(shell id -g)
GIT_PARAMETERS_REPOSITORY ?= $(call pop,$(GIT_UPSTREAM_REPOSITORY))/$(PARAMETERS)
GIT_REPOSITORY ?= $(if $(SUBREPO),$(shell awk -F ' = ' '$$1 ~ /^[[\s\t]]*remote$$/ {print $$2}' .gitrepo),$(shell git config --get remote.origin.url))
GIT_UPSTREAM_REPOSITORY ?= $(if $(findstring ://,$(GIT_REPOSITORY)),$(call pop,$(call pop,$(GIT_REPOSITORY)))/,$(call pop,$(GIT_REPOSITORY),:):)$(GIT_UPSTREAM_USER)/$(lastword $(subst /, ,$(GIT_REPOSITORY)))
GIT_UPSTREAM_USER ?= $(MONOREPO)
HOSTNAME ?= $(shell hostname |sed 's/\..*//')
MAKE_ARGS ?= $(foreach var,$(MAKE_VARS),$(if $($(var)),$(var)='$($(var))'))
MAKE_VARS ?= ENV
MAKECMDVARS ?= $(strip $(foreach var, $(filter-out .VARIABLES,$(.VARIABLES)), $(if $(filter command\ line,$(origin $(var))),$(var))))
MAKECMDARGS ?= $(foreach var,$(MAKECMDVARS),$(var)='$($(var))')
MAKETARGETS ?= $(filter-out $(.VARIABLES),$(shell $(MAKE) -qp |awk -F':' '/^[a-zA-Z0-9][^$$\#\/\t=]*:([^=]|$$)/ {print $$1}' |sort -u))
MONOREPO ?= $(if $(wildcard .git),$(if $(wildcard */.gitrepo),$(notdir $(CURDIR))),$(if $(SUBREPO),$(notdir $(realpath $(CURDIR)/..))))
MONOREPO_DIR ?= $(if $(wildcard .git),$(if $(wildcard */.gitrepo),$(CURDIR)),$(if $(SUBREPO),$(realpath $(CURDIR)/..)))
PARAMETERS ?= parameters
RECURSIVE ?= true
SHARED ?= shared
SUBREPO ?= $(if $(wildcard .gitrepo),$(notdir $(CURDIR)))
SUBREPO_DIR ?= $(if $(SUBREPO),$(CURDIR))
SUBREPO_COMMIT ?= $(if $(SUBREPO),$(shell git rev-parse subrepo/$(SUBREPO)/$(BRANCH) 2>/dev/null))
TAG ?= $(shell git tag -l --points-at $(BRANCH) 2>/dev/null)
UID ?= $(shell id -u)
USER ?= $(shell id -nu)
VERBOSE ?= true
VERSION ?= $(shell git describe --tags $(BRANCH) 2>/dev/null || git rev-parse $(BRANCH) 2>/dev/null)
ifeq ($(DOCKER), true)
ENV_ARGS = $(foreach var,$(ENV_VARS),$(if $($(var)),-e $(var)='$($(var))')) $(shell printenv |awk -F '=' 'NR == FNR { if($$1 !~ /^(\#|$$)/) { A[$$1]; next } } ($$1 in A) {print "-e "$$0}' .env.dist - 2>/dev/null)
else
ENV_ARGS = $(foreach var,$(ENV_VARS),$(if $($(var)),$(var)='$($(var))')) $(shell printenv |awk -F '=' 'NR == FNR { if($$1 !~ /^(\#|$$)/) { A[$$1]; next } } ($$1 in A)' .env.dist - 2>/dev/null)
endif
# Guess OS
ifeq ($(OSTYPE),cygwin)
HOST_SYSTEM := CYGWIN
else ifeq ($(OS),Windows_NT)
HOST_SYSTEM := WINDOWS
else
UNAME_S := $(shell uname -s 2>/dev/null)
ifeq ($(UNAME_S),Linux)
HOST_SYSTEM := LINUX
endif
ifeq ($(UNAME_S),Darwin)
HOST_SYSTEM := DARWIN
endif
endif
ifneq ($(DEBUG), true)
.SILENT:
endif
ifeq ($(DRYRUN), true)
ECHO = $(if $(filter $(DRYRUN_IGNORE),true),,printf '${COLOR_BROWN}$(APP)${COLOR_RESET}[${COLOR_GREEN}$(MAKELEVEL)${COLOR_RESET}] ${COLOR_BLUE}$@${COLOR_RESET}:${COLOR_RESET} '; echo)
ifeq ($(RECURSIVE), true)
DRYRUN_RECURSIVE := true
endif
endif
ifeq ($(HOST_SYSTEM),DARWIN)
define getent-group
$(shell dscl . -read /Groups/$(1) 2>/dev/null |awk '$$1 == "PrimaryGroupID:" {print $$2}')
endef
ifneq ($(DOCKER),true)
SED_SUFFIX='\'\''
endif
else
define getent-group
$(shell getent group $(1) 2>/dev/null |awk -F: '{print $$3}')
endef
endif
define conf
$(eval file := $(1))
$(eval block := $(2))
$(eval variable := $(3))
[ -r "$(file)" ] && while IFS='=' read -r key value; do \
case $${key} in \
\#*) \
continue; \
;; \
\[*\]) \
current_bloc="$${key##\[}"; \
current_bloc="$${current_bloc%%\]}"; \
[ -z "$(block)" ] && [ -z "$(variable)" ] && printf '%s\n' "$${current_bloc}" ||:; \
;; \
*) \
key=$${key%$${key##*[![:space:]]}}; \
value=$${value#$${value%%[![:space:]]*}}; \
if [ "$(block)" = "$${current_bloc}" ] && [ "$${key}" ]; then \
[ -z "$(variable)" ] && printf '%s=%s\n' "$${key}" "$${value}" ||:; \
[ "$(variable)" = "$${key}" ] && printf '%s\n' "$${value}" ||:; \
fi \
;; \
esac \
done < "$(file)"
endef
define force
while true; do [ $$(ps x |awk 'BEGIN {nargs=split("'"$$*"'",args)} $$field == args[1] { matched=1; for (i=1;i<=NF-field;i++) { if ($$(i+field) == args[i+1]) {matched++} } if (matched == nargs) {found++} } END {print found+0}' field=4) -eq 0 ] && $(ECHO) $(1) || sleep 1; done
endef
pop = $(patsubst %$(or $(2),/)$(lastword $(subst $(or $(2),/), ,$(1))),%,$(1))
define sed
$(call exec,sed -i $(SED_SUFFIX) '\''$(1)'\'' $(2))
endef
##
# function make
## call make with predefined options and variables
# 1st arg: make command line (targets and arguments)
# 2nd arg: directory to call make from
# 3rd arg: list of variables to pass to make (ENV by default)
# 4th arg: path to .env file with additional arguments to call make with (file must exist when calling make)
# add list of VARIABLE=VALUE from vars to MAKE_ARGS
# add list of arguments from file to MAKE_ARGS
# eval MAKE_DIR option to -C $(2) if $(2) given
# add current target to MAKE_OLDFILE (list of already fired targets)
# print command that will be run if VERBOSE mode
# actually run make command
# if DRYRUN_RECURSIVE mode, run make command in DRYRUN mode
define make
$(eval cmd := $(1))
$(eval dir := $(2))
$(eval vars := $(3))
$(eval file := $(4))
$(if $(vars),$(eval MAKE_ARGS += $(foreach var,$(vars),$(if $($(var)),$(var)='$($(var))'))))
$(if $(wildcard $(file)),$(eval MAKE_ARGS += $(shell cat $(file) |sed '/^$$/d; /^#/d; /=/!d; s/^[[\s\t]]*//; s/[[\s\t]]*=[[\s\t]]*/=/;' |awk -F '=' '{print $$1"='\''"$$2"'\''"}')))
$(eval MAKE_DIR := $(if $(dir),-C $(dir)))
$(eval MAKE_OLDFILE += $(filter-out $(MAKE_OLDFILE), $^))
$(if $(filter $(VERBOSE),true),printf '${COLOR_GREEN}Running${COLOR_RESET} "'"make $(MAKE_ARGS) $(cmd)"'" $(if $(dir),${COLOR_BLUE}in folder${COLOR_RESET} $(dir) )\n')
$(ECHO) $(MAKE) $(MAKE_DIR) $(patsubst %,-o %,$(MAKE_OLDFILE)) MAKE_OLDFILE="$(MAKE_OLDFILE)" $(MAKE_ARGS) $(cmd)
$(if $(filter $(DRYRUN_RECURSIVE),true),$(MAKE) $(MAKE_DIR) $(patsubst %,-o %,$(MAKE_OLDFILE)) MAKE_OLDFILE="$(MAKE_OLDFILE)" DRYRUN=$(DRYRUN) RECURSIVE=$(RECURSIVE) $(MAKE_ARGS) $(cmd))
endef
ifneq ($(MONOREPO),)
ifneq ($(wildcard .gitrepo),)
INFRA := ../infra
MAKE_SUBDIRS := subrepo
else
INFRA := infra
MAKE_SUBDIRS := monorepo
endif
endif
ifneq ($(APP),)
MAKE_SUBDIRS += apps $(foreach type,$(APP_TYPE),$(if $(wildcard $(MAKE_DIR)/apps/$(type)),apps/$(type)))
endif
# include .env files
include $(wildcard $(ENV_FILE))
# include variables definitions
include $(wildcard $(MAKE_DIR)/def.*.mk)
include $(foreach subdir,$(MAKE_SUBDIRS),$(wildcard $(MAKE_DIR)/$(subdir)/def.mk $(MAKE_DIR)/$(subdir)/def.*.mk))
# set ENV=$(env) for each target ending with :$(env) and call $* target
# set ../$(PARAMETERS)/$(env)/$(APP)/.env as last .env readed file to override values of .env file
define TARGET:ENV
.PHONY: $(TARGET)
$(TARGET): $(ASSIGN_ENV)
$(TARGET): $(ASSIGN_ENV_FILE)
$(TARGET):
$$(call make,$$*,,ENV_FILE)
endef
$(foreach env,$(ENV_LIST),$(eval TARGET := %\:$(env)) $(eval ASSIGN_ENV := ENV:=$(env)) $(eval ASSIGN_ENV_FILE := ENV_FILE+=$(wildcard ../$(PARAMETERS)/$(env)/$(APP)/.env)) $(eval $(TARGET:ENV)))
# set ENV=$(env) for each target ending with @$(env)
$(foreach env,$(ENV_LIST),$(eval %@$(env): ENV:=$(env)))
# Accept arguments for CMDS targets
ifneq ($(filter $(CMDS),$(firstword $(MAKECMDGOALS))),)
# set $ARGS with following arguments
ARGS := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS))
ARGS := $(subst :,\:,$(ARGS))
ARGS := $(subst &,\&,$(ARGS))
# ...and turn them into do-nothing targets
$(eval $(ARGS):;@:)
endif
+78
View File
@@ -0,0 +1,78 @@
##
# target .env:
# update .env file when .env.dist file is newer
.env: .env.dist
$(call .env,,,$(wildcard ../$(PARAMETERS)/$(ENV)/$(APP)/.env .env.$(ENV)))
# include .env file
-include .env
ifneq (,$(filter true,$(ENV_RESET)))
env_reset := -i
endif
SHELL:=/bin/bash
##
# function .env
## set .env file path and call .env_update function if .env.dist file exists
# 1st arg: path to .env file to update, default to .env
# 2nd arg: path to .env.dist file, default to .env.dist
# 3rd arg: path to .env override files, default to .env.$(ENV)
# if .env.dist exists then call .env_update function
define .env
$(eval env_file:=$(or $(1),.env))
$(eval env_dist:=$(or $(2),$(env_file).dist))
$(eval env_over:=$(or $(wildcard $(3)),$(wildcard $(env_file).$(ENV))))
$(if $(wildcard $(env_dist)), $(call .env_update))
endef
##
# function .env_update
## update .env file with vars from .env.dist not set in environment.
## this function adds variables from the .env.dist to the .env file
## and does substitution to replace variables with their value when
## adding it to the .env. It reads variables first from environment,
## make command line, .env override files and finish with .env.dist
## to do the substitution. It does not write to .env file variables
## that already exist in .env file or comes from system environment.
# create the .env file
# read environment variables
# keep variables from .env.dist that does not exist in environment
# add variables definition from .env override files at the beginning of the list
# add variables definition from make command line at the beginning of the list
# remove duplicate variables
# keep variables that exists in .env.dist
# keep variables that does not exist in .env
# read variables definition in a subshell with multiline support
# create a new environment (empty if $(ENV_RESET) is true)
# read environment variables and keep only those existing in .env.dist
# add .env overrides variables definition
# add .env.dist variables definition
# remove empty lines or comments
# remove duplicate variables
# replace variabless in stdin with their value from the new environment
# remove residual empty lines or comments
# sort alphabetically
# add variables definition to the .env file
define .env_update
touch $(env_file)
printenv \
|awk -F '=' 'NR == FNR { if($$1 !~ /^(#|$$)/) { A[$$1]; next } } !($$1 in A)' - $(env_dist) \
|cat $(env_over) - \
|awk 'BEGIN {split("$(MAKECMDVARS)",vars," "); for (var in vars) {print vars[var]"="ENVIRON[vars[var]]};} {print}' \
|awk -F '=' '!seen[$$1]++' \
|awk -F '=' 'ARGV[1] == FILENAME { A[$$1]; next } ($$1 in A)' $(env_dist) - 2>/dev/null \
|awk -F '=' 'ARGV[1] == FILENAME { A[$$1]; next } !($$1 in A)' $(env_file) - 2>/dev/null \
|(IFS=$$'\n'; \
env $(env_reset) \
$$(env |awk -F '=' 'NR == FNR { if($$1 !~ /^(#|$$)/) { A[$$1]; next } } ($$1 in A)' $(env_dist) - \
|cat - $(env_over) \
|cat - $(env_dist) \
|sed -e /^$$/d -e /^#/d \
|awk -F '=' '!seen[$$1]++') \
awk '{while(match($$0,"[$$]{[^}]*}")) {var=substr($$0,RSTART+2,RLENGTH-3);gsub("[$$]{"var"}",ENVIRON[var])} print}') \
|sed -e /^$$/d -e /^#/d \
|sort \
>> $(env_file)
endef
+39
View File
@@ -0,0 +1,39 @@
.DEFAULT_GOAL := help
COLOR_RESET ?= \033[0m
COLOR_GREEN ?= \033[32m
COLOR_BROWN ?= \033[33m
COLOR_BLUE ?= \033[36m
##
# HELP
.PHONY: help
help: usage blank1 target blank2 context ## This help
.PHONY: usage
usage:
printf "${COLOR_BROWN}Usage:${COLOR_RESET}\n"
printf "make [target]\n"
.PHONY: blank1 blank2
blank1 blank2:
printf "\n"
.PHONY: target
## Show available targets
target:
printf "${COLOR_BROWN}Targets:${COLOR_RESET}\n"
awk 'BEGIN {FS = ":.*?## "}; $$0 ~ /^[a-zA-Z_-]+:.*?## .*$$/ {printf "${COLOR_BLUE}%-30s${COLOR_RESET} %s\n", $$1, $$2}' $(MAKEFILE_LIST)
.PHONY: context
## Show current context
context:
printf "${COLOR_BROWN}Context:${COLOR_RESET}\n"
$(MAKE) $(CONTEXT)
.PHONY: $(CONTEXT)
$(CONTEXT):
@printf "${COLOR_BLUE}%-30s${COLOR_RESET} ${COLOR_GREEN}%s${COLOR_RESET}\n" $@ "$($@)"
.PHONY: print-%
print-%: ; @printf "${COLOR_BLUE}%-30s${COLOR_RESET} ${COLOR_GREEN}%s${COLOR_RESET}\n" $* "$($*)"
+5
View File
@@ -0,0 +1,5 @@
MAKE_DIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST))))
MAKE_FILES := env.mk def.mk
include $(wildcard $(patsubst %,$(MAKE_DIR)/%,$(MAKE_FILES))) $(filter-out $(wildcard $(patsubst %,$(MAKE_DIR)/%,include.mk def.*.mk $(MAKE_FILES))),$(wildcard $(MAKE_DIR)/*.mk))
include $(foreach subdir,$(MAKE_SUBDIRS),$(filter-out $(wildcard $(MAKE_DIR)/$(subdir)/def.mk $(MAKE_DIR)/$(subdir)/def.*.mk),$(wildcard $(MAKE_DIR)/$(subdir)/*.mk)))
include $(wildcard *.mk docker/*.mk stack/*.mk)
+8
View File
@@ -0,0 +1,8 @@
##
# INFRA
.PHONY: infra-%
infra-%: ;
ifneq ($(wildcard $(INFRA)),)
$(call make,$*,$(INFRA))
endif
+67
View File
@@ -0,0 +1,67 @@
##
# COMMON
.PHONY: build
build: $(APPS) ## Build applications
.PHONY: build@%
build@%: $(APPS);
.PHONY: clean
clean: $(APPS) ## Clean applications
.PHONY: clean@%
clean@%: $(APPS);
.PHONY: config
config: $(APPS)
.PHONY: copy
copy:
$(foreach app,$(APPS),$(foreach file,$(ARGS),$(if $(wildcard $(file)),$(ECHO) $(if $(filter LINUX,$(HOST_SYSTEM)),cp -a --parents $(file) $(app)/,rsync -a $(file) $(app)/$(file)) &&)) true &&) true
.PHONY: deploy
deploy: $(APPS) ## Deploy applications
.PHONY: deploy@%
deploy@%: $(APPS);
.PHONY: down
down: $(APPS) ## Remove application dockers
.PHONY: ps
ps: $(APPS)
.PHONY: rebuild
rebuild: $(APPS) ## Rebuild applications
.PHONY: recreate
recreate: $(APPS) ## Recreate applications
.PHONY: reinstall
reinstall: $(APPS) ## Reinstall applications
.PHONY: restart
restart: $(APPS) ## Restart applications
.PHONY: start
start: $(APPS) ## Start applications
.PHONY: stop
stop: $(APPS) ## Stop applications
.PHONY: tests
tests: $(APPS) ## Test applications
.PHONY: up
up: $(APPS) ## Create application dockers
.PHONY: $(APPS)
$(APPS):
$(if $(wildcard $@/Makefile), \
$(call make,-o install-infra $(patsubst apps-%,%,$(MAKECMDGOALS)) STATUS=0,$(patsubst %/,%,$@),ENV_SUFFIX), \
printf "${COLOR_BROWN}WARNING${COLOR_RESET}: ${COLOR_GREEN}no app available in folder${COLOR_RESET} $@.\n" >&2)
# run targets in $(APPS)
.PHONY: apps-%
apps-%: $(APPS) ; ## run % targets in $(APPS)
+15
View File
@@ -0,0 +1,15 @@
ifneq (,$(filter true,$(DRONE)))
# limit to APPS impacted by the commit
ifneq (,$(filter $(DRONE_BUILD_EVENT),pull_request push))
COMMIT_AFTER := $(DRONE_COMMIT_AFTER)
COMMIT_BEFORE := $(if $(filter 0000000000000000000000000000000000000000,$(DRONE_COMMIT_BEFORE)),upstream/master,$(DRONE_COMMIT_BEFORE))
endif
ifneq (,$(filter $(DRONE_BUILD_EVENT),tag))
COMMIT_AFTER := $(DRONE_TAG)
COMMIT_BEFORE := $(shell git describe --abbrev=0 --tags $(DRONE_TAG)^)
endif
APPS_IMPACTED := $(shell git diff --name-only $(COMMIT_BEFORE) $(COMMIT_AFTER) 2>/dev/null |awk -F '/' 'NF>1 && !seen[$$1]++ {print $$1}')
# prevent drone to make down in infra
APPS := $(if $(filter-out down,$(MAKECMDGOALS)),$(filter $(INFRA),$(APPS_IMPACTED))) $(sort $(filter-out $(DIRS) $(INFRA),$(APPS_IMPACTED)))
CONTEXT += DRONE_BRANCH DRONE_BUILD_EVENT DRONE_BUILD_NUMBER DRONE_COMMIT_AFTER DRONE_COMMIT_AUTHOR DRONE_COMMIT_AUTHOR_EMAIL DRONE_COMMIT_BEFORE DRONE_COMMIT_REF GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME
endif
+8
View File
@@ -0,0 +1,8 @@
APPS ?= $(INFRA) $(sort $(filter-out $(DIRS) $(INFRA), $(patsubst %/,%,$(wildcard */)) ))
APPS_NAME ?= $(foreach app,$(APPS),$(or $(shell awk -F '=' '$$1 == "APP" {print $$2}' $(or $(wildcard $(app)/.env),$(wildcard $(app)/.env.$(ENV)),$(app)/.env.dist) 2>/dev/null),$(app)))
CMDS += copy master-tag release release-check release-create release-finish subrepo-push update-subrepo
CONTEXT += APPS APPS_NAME ENV RELEASE_INSTALL
DIRS ?= $(MAKE_DIR) $(PARAMETERS) $(SHARED)
RELEASE_UPGRADE ?= $(filter v%, $(shell git tag -l |sort -V |awk '/$(RELEASE_INSTALL)/,0'))
RELEASE_VERSION ?= $(firstword $(subst -, ,$(VERSION)))
SUBREPOS ?= $(filter subrepo/%, $(shell git remote))
+85
View File
@@ -0,0 +1,85 @@
##
# GIT
## Check if monorepo is up to date with subrepo. subrepo-push saves the parent commit in .gitrepo
.PHONY: git-diff-subrepo
git-diff-subrepo: infra-base subrepo-check
## Get parent commit in .gitrepo : awk '$1 == "parent" {print $3}' subrepo/.gitrepo
## Get child of parent commit : git rev-list --ancestry-path parent..HEAD |tail -n 1
## Compare child commit with our tree : git diff --quiet child -- subrepo
$(eval DRYRUN_IGNORE := true)
$(eval DIFF = $(shell $(call exec,git diff --quiet $(shell $(call exec,git rev-list --ancestry-path $(shell awk '$$1 == "parent" {print $$3}' $(SUBREPO)/.gitrepo)..HEAD |tail -n 1)) -- $(SUBREPO); echo $$?)) )
$(eval DRYRUN_IGNORE := false)
.PHONY: git-fetch-subrepo
git-fetch-subrepo: infra-base subrepo-check
$(call exec,git fetch --prune $(REMOTE))
.PHONY: git-stash
git-stash: infra-base git-status
if [ ! $(STATUS) -eq 0 ]; then \
$(call exec,git stash); \
fi
.PHONY: git-status
git-status: infra-base
$(eval DRYRUN_IGNORE := true)
$(eval STATUS := $(shell $(call exec,git status -uno --porcelain 2>/dev/null |wc -l)))
$(eval DRYRUN_IGNORE := false)
.PHONY: git-unstash
git-unstash: infra-base
$(eval STATUS ?= 0)
if [ ! $(STATUS) -eq 0 ]; then \
$(call exec,git stash pop); \
fi
# Create branch $(BRANCH) from upstream/$* branch
.PHONY: branch-create-upstream-%
branch-create-upstream-%: infra-base update-upstream
$(call exec,git fetch --prune upstream)
$(call exec,git rev-parse --verify $(BRANCH) >/dev/null 2>&1 && echo Unable to create $(BRANCH). || git branch $(BRANCH) upstream/$*)
$(call exec,[ $$(git ls-remote --heads upstream $(BRANCH) |wc -l) -eq 0 ] && git push upstream $(BRANCH) || echo Unable to create branch $(BRANCH) on remote upstream.)
$(call exec,git checkout $(BRANCH))
# Delete branch $(BRANCH)
.PHONY: branch-delete
branch-delete: infra-base update-upstream
$(call exec,git rev-parse --verify $(BRANCH) >/dev/null 2>&1 && git branch -d $(BRANCH) || echo Unable to delete branch $(BRANCH).)
$(foreach remote,upstream, $(call exec,[ $$(git ls-remote --heads $(remote) $(BRANCH) |wc -l) -eq 1 ] && git push $(remote) :$(BRANCH) || echo Unable to delete branch $(BRANCH) on remote $(remote).) &&) true
# Merge branch $(BRANCH) into upstream/$* branch
.PHONY: branch-merge-upstream-%
branch-merge-upstream-%: infra-base update-upstream
$(call exec,git rev-parse --verify $(BRANCH) >/dev/null 2>&1)
$(call exec,git checkout $(BRANCH))
$(call exec,git pull --ff-only upstream $(BRANCH))
$(call exec,git push upstream $(BRANCH))
$(call exec,git checkout $*)
$(call exec,git pull --ff-only upstream $*)
$(call exec,git merge --no-ff --no-edit $(BRANCH))
$(call exec,git push upstream $*)
# Create $(TAG) tag to reference upstream/$* branch
.PHONY: tag-create-upstream-%
tag-create-upstream-%: infra-base update-upstream
ifneq ($(words $(TAG)),0)
$(call exec,git checkout $*)
$(call exec,git pull --tags --prune upstream $*)
$(call sed,s/^##\? $(TAG).*/## $(TAG) - $(shell date +%Y-%m-%d)/,CHANGELOG.md)
$(call exec,[ $$(git diff CHANGELOG.md 2>/dev/null |wc -l) -eq 0 ] || git commit -m "$$(cat CHANGELOG.md |sed -n '\''/$(TAG)/,/^$$/{s/##\(.*\)/release\1\n/;p;}'\'')" CHANGELOG.md)
$(call exec,[ $$(git tag -l $(TAG) |wc -l) -eq 0 ] || git tag -d $(TAG))
$(call exec,git tag $(TAG))
$(call exec,[ $$(git ls-remote --tags upstream $(TAG) |wc -l) -eq 0 ] || git push upstream :refs/tags/$(TAG))
$(call exec,git push --tags upstream $*)
endif
# Merge tag $(TAG) into upstream/$* branch
.PHONY: tag-merge-upstream-%
tag-merge-upstream-%: infra-base update-upstream
ifneq ($(words $(TAG)),0)
$(call exec,git fetch --tags -u --prune upstream $*:$*)
$(call exec,git checkout $*)
$(call exec,git merge --ff --no-edit $(TAG))
$(call exec,git push upstream $*)
endif
+11
View File
@@ -0,0 +1,11 @@
##
# INSTALL
.PHONY: install-infra
install-infra: infra-install
.PHONY: install-$(SHARED)
install-$(SHARED): $(SHARED)
$(SHARED):
$(ECHO) mkdir -p $(SHARED)
+35
View File
@@ -0,0 +1,35 @@
##
# RELEASE
.PHONY: release
release: release-create # Create release [version]
.PHONY: release-check
release-check:
ifneq ($(words $(ARGS)),0)
$(eval RELEASE_VERSION := $(word 1, $(ARGS)))
$(eval RELEASE_BRANCH := release/$(RELEASE_VERSION))
else
ifneq ($(findstring $(firstword $(subst /, ,$(BRANCH))),release),)
$(eval RELEASE_BRANCH := $(BRANCH))
$(eval RELEASE_VERSION := $(word 2, $(subst /, ,$(BRANCH))))
endif
endif
$(if $(filter VERSION=%,$(MAKEFLAGS)), $(eval RELEASE_VERSION:=$(VERSION)) $(eval RELEASE_BRANCH := release/$(RELEASE_VERSION)))
$(if $(findstring $(firstword $(subst /, ,$(RELEASE_BRANCH))),release),,$(error Please provide a VERSION or a release BRANCH))
.PHONY: release-create
release-create: release-check git-stash ## Create release [version]
$(call make,branch-create-upstream-develop BRANCH=$(RELEASE_BRANCH))
$(call make,git-unstash,,STATUS)
.PHONY: release-finish
release-finish: release-check git-stash ## Finish release [version]
$(call make,branch-merge-upstream-master BRANCH=$(RELEASE_BRANCH))
$(call make,update-subrepos)
$(call make,tag-create-upstream-master TAG=$(RELEASE_VERSION))
$(call make,subrepos-tag-create-master TAG=$(RELEASE_VERSION))
$(call make,tag-merge-upstream-develop TAG=$(RELEASE_VERSION))
$(call make,branch-delete BRANCH=$(RELEASE_BRANCH))
$(call make,subrepos-branch-delete BRANCH=$(RELEASE_BRANCH))
$(call make,git-unstash,,STATUS)
+59
View File
@@ -0,0 +1,59 @@
##
# SUBREPO
.PHONY: subrepo-check
subrepo-check:
ifeq ($(words $(ARGS)), 0)
ifeq ($(words $(SUBREPO)), 0)
$(error Please provide a SUBREPO)
endif
endif
$(eval SUBREPO ?= $(word 1, $(ARGS)))
$(eval REMOTE := subrepo/$(SUBREPO))
## Delete branch $(BRANCH) on $(SUBREPO) remote
.PHONY: subrepo-branch-delete
subrepo-branch-delete: infra-base subrepo-check
ifneq ($(words $(BRANCH)),0)
$(call exec,[ $$(git ls-remote --heads $(REMOTE) $(BRANCH) |wc -l) -eq 1 ] && git push $(REMOTE) :$(BRANCH) || echo Unable to delete branch $(BRANCH) on remote $(REMOTE).)
endif
.PHONY: subrepo-tag-create-%
subrepo-tag-create-%: infra-base subrepo-check git-fetch-subrepo ## Create $(TAG) tag to reference $(REMOTE)/$* branch
ifneq ($(words $(TAG)),0)
$(call exec,[ $$(git ls-remote --tags $(REMOTE) $(TAG) |wc -l) -eq 0 ] || git push $(REMOTE) :refs/tags/$(TAG))
$(call exec,git push $(REMOTE) refs/remotes/subrepo/$(SUBREPO)/$*:refs/tags/$(TAG))
endif
## Push to subrepo.
.PHONY: subrepo-push
subrepo-push: infra-base subrepo-check git-fetch-subrepo git-diff-subrepo
# update .gitrepo only on master branch
ifeq ($(BRANCH),master)
$(eval UPDATE_SUBREPO_OPTIONS += -u)
endif
# if release|story|hotfix branch, delete remote branch before push and recreate it from master
ifneq ($(findstring $(firstword $(subst /, ,$(BRANCH))),release story hotfix),)
$(eval DRYRUN_IGNORE := true)
$(eval DELETE = $(shell $(call exec,git ls-remote --heads $(REMOTE) $(BRANCH) |wc -l)) )
$(eval DRYRUN_IGNORE := false)
else
$(eval DELETE = 0)
endif
if [ $(DIFF) -eq 0 ]; then \
echo subrepo $(SUBREPO) already up to date.; \
else \
if [ $(DELETE) -eq 1 ]; then \
$(call exec,git push $(REMOTE) :$(BRANCH)); \
$(call exec,git push $(REMOTE) refs/remotes/$(REMOTE)/master:refs/heads/$(BRANCH)); \
fi; \
$(call exec,git subrepo fetch $(SUBREPO) -b $(BRANCH)); \
$(call exec,git subrepo push $(SUBREPO) -b $(BRANCH) $(UPDATE_SUBREPO_OPTIONS)); \
$(call exec,git subrepo clean $(SUBREPO)); \
fi
.PHONY: subrepos-branch-delete
subrepos-branch-delete: $(APPS) ;
.PHONY: subrepos-tag-create-%
subrepos-tag-create-%: $(APPS) ;
+47
View File
@@ -0,0 +1,47 @@
##
# UPDATE
## Update /etc/hosts
.PHONY: update-hosts
update-hosts:
ifneq (,$(filter $(ENV),local))
cat */.env 2>/dev/null |grep -Eo 'urlprefix-[^/]+' |sed 's/urlprefix-//' |while read host; do grep $$host /etc/hosts >/dev/null 2>&1 || { echo "Adding $$host to /etc/hosts"; echo 127.0.0.1 $$host |$(ECHO) sudo tee -a /etc/hosts >/dev/null; }; done
endif
.PHONY: update-$(PARAMETERS)
update-$(PARAMETERS): $(PARAMETERS)
$(PARAMETERS): SSH_PUBLIC_HOST_KEYS := $(PARAMETERS_REMOTE_HOST) $(SSH_BASTION_HOSTNAME) $(SSH_REMOTE_HOSTS)
$(PARAMETERS): MAKE_VARS += SSH_BASTION_HOSTNAME SSH_BASTION_USERNAME SSH_PRIVATE_IP_RANGE SSH_PUBLIC_HOST_KEYS
$(PARAMETERS): infra-base
$(call exec,[ -d $(PARAMETERS) ] && cd $(PARAMETERS) && git pull --quiet || git clone --quiet $(GIT_PARAMETERS_REPOSITORY))
## Update release version number in .env
.PHONY: update-release
update-release:
$(ECHO) awk -v s=RELEASE_INSTALL=$(RELEASE_VERSION) '/^RELEASE_INSTALL=/{$$0=s;f=1} {a[++n]=$$0} END{if(!f)a[++n]=s;for(i=1;i<=n;i++)print a[i]>ARGV[1]}' .env
## Update remotes
.PHONY: update-remotes
update-remotes: infra-base
$(call exec,git fetch --all --prune --tags -u)
.PHONY: update-remote-%
update-remote-%: infra-base
$(call exec,git fetch --prune --tags -u $*)
## Update subrepos
.PHONY: update-subrepos
update-subrepos: infra-base git-stash $(APPS) git-unstash ## Update subrepos
$(call exec,git push upstream $(BRANCH))
.PHONY: update-subrepo-%
update-subrepo-%:
$(if $(wildcard $*/Makefile),$(call make,update-subrepo,$*))
.PHONY: update-upstream
update-upstream: infra-base .git/refs/remotes/upstream/master
$(call exec,git fetch --tags upstream)
.git/refs/remotes/upstream/master: infra-base
$(call exec,git remote add upstream $(GIT_UPSTREAM_REPOSITORY) 2>/dev/null ||:)
+9
View File
@@ -0,0 +1,9 @@
##
# UPGRADE
.PHONY: upgrade
upgrade: $(patsubst %,upgrade-from-release-%,$(RELEASE_UPGRADE)) update-release ## Update monorepo version
.PHONY: upgrade-from-release-%
upgrade-from-release-%:
# echo "Upgrading from release: $*"
+23
View File
@@ -0,0 +1,23 @@
## Update subrepos
.PHONY: update-subrepo update-subrepos
update-subrepo update-subrepos: bootstrap-git git-stash subrepos-push git-unstash
.PHONY: subrepos-branch-delete
subrepos-branch-delete:
$(call make,subrepo-branch-delete,..,SUBREPO BRANCH)
.PHONY: subrepos-tag-create-%
subrepos-tag-create-%:
$(call make,subrepo-tag-create-$*,..,SUBREPO TAG)
.PHONY: subrepos-push
subrepos-push:
$(call make,subrepo-push,..,SUBREPO BRANCH)
.PHONY: git-stash
git-stash:
$(call make,git-stash,..)
.PHONY: git-unstash
git-unstash:
$(call make,git-unstash,..)
+134
View File
@@ -0,0 +1,134 @@
################################################################################
#
# This file contains various utility macros and variables used about
# everywhere in make constructs.
#
################################################################################
# source : https://raw.githubusercontent.com/buildroot/buildroot/master/support/misc/utils.mk
# Strip quotes and then whitespaces
qstrip = $(strip $(subst ",,$(1)))
#"))
# Variables for use in Make constructs
comma := ,
empty :=
space := $(empty) $(empty)
# make 4.3:
# https://lwn.net/Articles/810071/
# Number signs (#) appearing inside a macro reference or function invocation
# no longer introduce comments and should not be escaped with backslashes:
# thus a call such as:
# foo := $(shell echo '#')
# is legal. Previously the number sign needed to be escaped, for example:
# foo := $(shell echo '\#')
# Now this latter will resolve to "\#". If you want to write makefiles
# portable to both versions, assign the number sign to a variable:
# H := \#
# foo := $(shell echo '$H')
SHARP_SIGN := \#
# Case conversion macros. This is inspired by the 'up' macro from gmsl
# (http://gmsl.sf.net). It is optimised very heavily because these macros
# are used a lot. It is about 5 times faster than forking a shell and tr.
#
# The caseconvert-helper creates a definition of the case conversion macro.
# After expansion by the outer $(eval ), the UPPERCASE macro is defined as:
# $(strip $(eval __tmp := $(1)) $(eval __tmp := $(subst a,A,$(__tmp))) ... )
# In other words, every letter is substituted one by one.
#
# The caseconvert-helper allows us to create this definition out of the
# [FROM] and [TO] lists, so we don't need to write down every substition
# manually. The uses of $ and $$ quoting are chosen in order to do as
# much expansion as possible up-front.
#
# Note that it would be possible to conceive a slightly more optimal
# implementation that avoids the use of __tmp, but that would be even
# more unreadable and is not worth the effort.
[FROM] := a b c d e f g h i j k l m n o p q r s t u v w x y z - .
[TO] := A B C D E F G H I J K L M N O P Q R S T U V W X Y Z _ _
define caseconvert-helper
$(1) = $$(strip \
$$(eval __tmp := $$(1))\
$(foreach c, $(2),\
$$(eval __tmp := $$(subst $(word 1,$(subst :, ,$c)),$(word 2,$(subst :, ,$c)),$$(__tmp))))\
$$(__tmp))
endef
$(eval $(call caseconvert-helper,UPPERCASE,$(join $(addsuffix :,$([FROM])),$([TO]))))
$(eval $(call caseconvert-helper,LOWERCASE,$(join $(addsuffix :,$([TO])),$([FROM]))))
# Reverse the orders of words in a list. Again, inspired by the gmsl
# 'reverse' macro.
reverse = $(if $(1),$(call reverse,$(wordlist 2,$(words $(1)),$(1))) $(firstword $(1)))
# Sanitize macro cleans up generic strings so it can be used as a filename
# and in rules. Particularly useful for VCS version strings, that can contain
# slashes, colons (OK in filenames but not in rules), and spaces.
sanitize = $(subst $(space),_,$(subst :,_,$(subst /,_,$(strip $(1)))))
# MESSAGE Macro -- display a message in bold type
MESSAGE = echo "$(TERM_BOLD)>>> $($(PKG)_NAME) $($(PKG)_VERSION) $(call qstrip,$(1))$(TERM_RESET)"
TERM_BOLD := $(shell tput smso 2>/dev/null)
TERM_RESET := $(shell tput rmso 2>/dev/null)
# Utility functions for 'find'
# findfileclauses(filelist) => -name 'X' -o -name 'Y'
findfileclauses = $(call notfirstword,$(patsubst %,-o -name '%',$(1)))
# finddirclauses(base, dirlist) => -path 'base/dirX' -o -path 'base/dirY'
finddirclauses = $(call notfirstword,$(patsubst %,-o -path '$(1)/%',$(2)))
# Miscellaneous utility functions
# notfirstword(wordlist): returns all but the first word in wordlist
notfirstword = $(wordlist 2,$(words $(1)),$(1))
# build a comma-separated list of quoted items, from a space-separated
# list of unquoted items: a b c d --> "a", "b", "c", "d"
make-comma-list = $(subst $(space),$(comma)$(space),$(patsubst %,"%",$(strip $(1))))
# Needed for the foreach loops to loop over the list of hooks, so that
# each hook call is properly separated by a newline.
define sep
endef
PERCENT = %
QUOTE = '
# ' # Meh... syntax-highlighting
# This macro properly escapes a command string, then prints it with printf:
#
# - first, backslash '\' are self-escaped, so that they do not escape
# the following char and so that printf properly outputs a backslash;
#
# - next, single quotes are escaped by closing an existing one, adding
# an escaped one, and re-openning a new one (see below for the reason);
#
# - then '%' signs are self-escaped so that the printf does not interpret
# them as a format specifier, in case the variable contains an actual
# printf with a format;
#
# - finally, $(sep) is replaced with the literal '\n' so that make does
# not break on the so-expanded variable, but so that the printf does
# correctly output an LF.
#
# Note: this must be escaped in this order to avoid over-escaping the
# previously escaped elements.
#
# Once everything has been escaped, it is passed between single quotes
# (that's why the single-quotes are escaped they way they are, above,
# and why the dollar sign is not escaped) to printf(1). A trailing
# newline is apended, too.
#
# Note: leading or trailing spaces are *not* stripped.
#
define PRINTF
printf '$(subst $(sep),\n,\
$(subst $(PERCENT),$(PERCENT)$(PERCENT),\
$(subst $(QUOTE),$(QUOTE)\$(QUOTE)$(QUOTE),\
$(subst \,\\,$(1)))))\n'
endef