diff --git a/Makefile b/Makefile index 69d665a..9441e78 100644 --- a/Makefile +++ b/Makefile @@ -1,114 +1,140 @@ -SHA1 := $(shell git rev-parse --short HEAD) -DOCKER_IMAGE ?= gogo -DOCKER_TAG ?= latest - -DOCKER_BUILD_ARGS := -t $(DOCKER_IMAGE) - -ifdef CACHE_FROM -DOCKER_BUILD_ARGS := --cache-from $(CACHE_FROM) $(DOCKER_BUILD_ARGS) +ROOT_DIR := $(shell git rev-parse --show-toplevel) +VENV_CMD := python3 -m venv +VENV_DIR := $(ROOT_DIR)/.venv +VENV_BIN := $(VENV_DIR)/bin + +# Docker Build Flags +DOCKER ?= $(shell which docker) +DOCKERFILE ?= . + +# gogo Application +GOGO_DOCKER_IMAGE ?= gogo +GOGO_DOCKER_TAG ?= latest +GOGO_DOCKER_CONTAINER_NAME ?= gogo-dev +GOGO_HOST ?= $(GOGO_DOCKER_CONTAINER_NAME) + +# TODO: Extend for Google OAuth support +ifeq ($(AUTH_HEADER_NAME),) + SKIP_AUTH ?= true +else + SKIP_AUTH ?= false + AUTH_HEADER_NAME_ENV := --env AUTH_HEADER_NAME=$(AUTH_HEADER_NAME) endif -define DOCKER_RUN_ARGS ---name $(DOCKER_IMAGE) \ ---publish 80:80 \ ---env CONFIG=DevelopmentConfig \ ---env DATABASE_URI_KMS=$(DATABASE_URI_KMS) \ ---env BASE_URL=http://localhost \ ---env-file envfile \ ---hostname gogo-dev \ ---volume $(HOME)/.aws:/root/.aws \ ---link gogo-postgres \ --it -endef - -.PHONY: run stop venv - -run: stop - @touch envfile - @docker ps | grep gogo-postgres > /dev/null || $(MAKE) db - @docker run $(DOCKER_RUN_ARGS) $(DOCKER_IMAGE) - +# Database +PG_DOCKER_IMAGE ?= postgres +PG_DOCKER_TAG ?= 10.0 +PG_DOCKER_CONTAINER_NAME ?= gogo-postgres +PG_HOST := $(PG_DOCKER_CONTAINER_NAME) +PG_USER := gogo +PG_PASS := gogo +PG_DB := gogo +PG_DATA := /var/lib/postgresql/data/gogo + +# GoGo Application +.PHONY: docker_build +docker_build: + $(DOCKER) build $(DOCKERFILE) -t $(GOGO_DOCKER_IMAGE):$(GOGO_DOCKER_TAG) + +.PHONY: run +run: stop docker_build + $(DOCKER) ps | grep $(PG_DOCKER_CONTAINER_NAME) > /dev/null || $(MAKE) db + $(DOCKER) run \ + --name $(GOGO_DOCKER_CONTAINER_NAME) \ + --hostname $(GOGO_HOST) \ + --publish 80:80 \ + --publish 443:443 \ + --env CONFIG=DevelopmentConfig \ + --env SKIP_AUTH=$(SKIP_AUTH) \ + $(AUTH_HEADER_NAME_ENV) \ + --env DATABASE_URI=postgresql://$(PG_USER):$(PG_PASS)@$(PG_HOST)/$(PG_DB) \ + --volume $(HOME)/.aws:/root/.aws \ + --link $(PG_DOCKER_CONTAINER_NAME):$(PG_HOST) \ + -it $(GOGO_DOCKER_IMAGE):$(GOGO_DOCKER_TAG) + +.PHONY: stop stop: - @docker rm -f $(DOCKER_IMAGE) > /dev/null 2>&1 || true - -venv: - @echo "Creating and updating venv." - @python3 -m venv .venv - @if [ "$$(cat resources/requirements.txt | sort)" != "$$(.venv/bin/pip freeze)" ]; then \ - .venv/bin/pip install -Ur resources/requirements.txt; \ - fi - -# Database. - -PGDB=gogo -PGHOST=localhost -PGPORT=5432 -PGUSER=gogo -PGPASS=changeme # for dev only. Prod password is encrypted in KMS via DATABASE_URI_KMS -PGDATA=/var/lib/postgresql/data/gogo - -define PG_ARGS ---name gogo-postgres \ ---env POSTGRES_USER=$(PGUSER) \ ---env POSTGRES_PASSWORD=$(PGPASS) \ ---env POSTGRES_DB=$(PGDB) \ ---env PGDATA=$(PGDATA) \ ---volume $(HOME)/data/gogo:$(PGDATA) \ ---detach -endef - -export PG_ARGS - -.PHONY: db db-truncate db-wipe psql db-run-command db-run-file db-apply-schema + $(DOCKER) rm -f $(GOGO_DOCKER_CONTAINER_NAME) > /dev/null 2>&1 || true +# Postgres Database +.PHONY: db db: - @echo "Launching Postgres." - @docker rm -f gogo-postgres > /dev/null 2>&1 || true - @docker run $$PG_ARGS postgres:10.0 > /dev/null - @echo "Waiting for Postgres to be ready." - @while true; do \ - docker exec gogo-postgres pg_isready -U $(PGUSER) -d $(PGDB) --quiet && break; \ + @echo "Launching Postgres..." + $(DOCKER) rm -f $(PG_DOCKER_CONTAINER_NAME) > /dev/null 2>&1 || true + $(DOCKER) run \ + --name $(PG_DOCKER_CONTAINER_NAME) \ + --hostname $(PG_HOST) \ + --env POSTGRES_USER=$(PG_USER) \ + --env POSTGRES_PASSWORD=$(PG_PASS) \ + --env POSTGRES_DB=$(PG_DB) \ + --env PGDATA=$(PG_DATA) \ + --volume $(HOME)/data/gogo:$(PG_DATA) \ + --detach $(PG_DOCKER_IMAGE):$(PG_DOCKER_TAG) > /dev/null + @echo "Waiting for Postgres to be ready..." + while true; do \ + /bin/echo -n "." ; \ + docker exec $(PG_DOCKER_CONTAINER_NAME) pg_isready -U $(PG_USER) -d $(PG_DB) --quiet && break; \ sleep 1; \ - done - @echo "Waiting for $(PGUSER) role to exist." - @while true; do \ + done ; /bin/echo + @echo "Waiting for $(PG_USER) role to exist..." + while true; do \ + /bin/echo -n "." ; \ COMMAND="SELECT 1" $(MAKE) db-run-command > /dev/null 2>&1 && break; \ sleep 1; \ - done + done ; /bin/echo @$(MAKE) db-apply-schema +.PHONY: db-truncate db-truncate: - @echo "Truncating database." + @echo "Truncating database..." @COMMAND='TRUNCATE shortcut;' $(MAKE) db-run-command +.PHONY: db-wipe db-wipe: - @echo "Wiping database." - @docker exec gogo-postgres dropdb -U $(PGUSER) $(PGDB) - @docker exec gogo-postgres createdb -U $(PGUSER) $(PGDB) + @echo "Wiping database..." + $(DOCKER) exec $(PG_DOCKER_CONTAINER_NAME) dropdb -U $(PG_USER) $(PG_DB) + $(DOCKER) exec $(PG_DOCKER_CONTAINER_NAME) createdb -U $(PG_USER) $(PG_DB) +.PHONY: psql psql: - @docker exec -it gogo-postgres psql \ - -U $(PGUSER) \ - -d $(PGDB) + $(DOCKER) exec -it $(PG_DOCKER_CONTAINER_NAME) psql \ + -U $(PG_USER) \ + -d $(PG_DB) +.PHONY: db-run-command db-run-command: - @docker exec gogo-postgres psql \ - -U $(PGUSER) \ - -d $(PGDB) \ + $(DOCKER) exec $(PG_DOCKER_CONTAINER_NAME) psql \ + -U $(PG_USER) \ + -d $(PG_DB) \ -c "$$COMMAND" +.PHONY: db-run-file db-run-file: - @docker cp $$SQL_FILE gogo-postgres:/sql_file.sql - @docker exec gogo-postgres psql \ + $(DOCKER) cp $$SQL_FILE $(PG_DOCKER_CONTAINER_NAME):/sql_file.sql + $(DOCKER) exec $(PG_DOCKER_CONTAINER_NAME) psql \ -f /sql_file.sql \ - -U $(PGUSER) \ - -d $(PGDB) + -U $(PG_USER) \ + -d $(PG_DB) +.PHONY: db-apply-schema db-apply-schema: @if COMMAND='\d' $(MAKE) db-run-command | grep 'row' > /dev/null; then \ echo "Schema already applied. Use 'make db-wipe' to reset all data."; \ else \ - echo "Applying schema."; \ + echo "Applying schema..."; \ SQL_FILE=schema/schema.sql $(MAKE) db-run-file; \ fi + +# Dev Env +.PHONY: venv +venv: $(VENV_BIN)/activate + if [ "$$(cat resources/requirements.txt | sort)" != "$$($(VENV_BIN)/pip freeze)" ]; then \ + $(VENV_BIN)/pip install -Ur resources/requirements.txt; \ + fi + +$(VENV_BIN)/activate: + @echo "Creating and updating venv..." + $(VENV_CMD) $(VENV_DIR) + $(VENV_BIN)/python -m pip install -U pip setuptools wheel + $(VENV_BIN)/pip install black isort diff --git a/src/gogo.py b/src/gogo.py index 4731e46..4f449d0 100644 --- a/src/gogo.py +++ b/src/gogo.py @@ -1,4 +1,5 @@ """URL shortcut generator.""" +import logging import os import flask @@ -10,7 +11,7 @@ # Shortcuts may not use these names. RESERVED_NAMES = {"_create", "_delete", "_edit", "_list", "_ajax"} -HTTPS_REDIRECT_URL = os.getenv("HTTPS_REDIRECT_URL", "https://localhost:8443") +HTTPS_REDIRECT_URL = os.getenv("HTTPS_REDIRECT_URL", "https://localhost") class DashboardView(BaseListView): @@ -182,5 +183,5 @@ def get(self): db.engine.execute("SELECT 1") return "OK" except Exception as e: - print("Healthz failed: %s" % e) + logging.getLogger(__name__).error("Healthz failed: %s", e) return "Fail", 500