cli-migrations,ci: add config v3 image

GitOrigin-RevId: ee04d046fd70355495fb18976ebfcca00454c0da
This commit is contained in:
Aravind K P 2021-04-06 15:28:24 +05:30 committed by hasura-bot
parent 78827b2f72
commit 1cc3a66fef
31 changed files with 486 additions and 49 deletions

View File

@ -123,6 +123,24 @@ push_latest_cli_migrations_image_v2() {
docker push "$LATEST_IMAGE_TAG"
}
# build and push container for auto-migrations-v3
build_and_push_cli_migrations_image_v3() {
IMAGE_TAG="hasura/graphql-engine:${CIRCLE_TAG}.cli-migrations-v3"
docker load -i /build/_cli_migrations_output/v3.tar
docker tag cli-migrations-v3 "$IMAGE_TAG"
docker push "$IMAGE_TAG"
}
# build and push latest container for auto-migrations-v3
push_latest_cli_migrations_image_v3() {
IMAGE_TAG="hasura/graphql-engine:${CIRCLE_TAG}.cli-migrations-v3"
LATEST_IMAGE_TAG="hasura/graphql-engine:latest.cli-migrations-v3"
# push latest.cli-migrations-v3 tag
docker tag "$IMAGE_TAG" "$LATEST_IMAGE_TAG"
docker push "$LATEST_IMAGE_TAG"
}
# copy docker-compose-https manifests to gcr for digital ocean one-click app
deploy_do_manifests() {
@ -177,12 +195,14 @@ deploy_console
deploy_server
if [[ ! -z "$CIRCLE_TAG" ]]; then
build_and_push_cli_migrations_image_v2
build_and_push_cli_migrations_image_v3
# if this is a stable release, update all latest assets
if [ $IS_STABLE_RELEASE = true ]; then
deploy_server_latest
push_server_binary
push_latest_cli_migrations_image_v2
push_latest_cli_migrations_image_v3
send_pr_to_repo graphql-engine-heroku
deploy_do_manifests
fi

View File

@ -39,6 +39,7 @@ While we want to fix this by offering, in the future, an explicit API that allow
- console: data sidebar bug fixes and improvements (#921)
- cli: fix seeds incorrectly being applied to databases in config v3 (#6683)
- cli: add `--all-databases` flag for `migrate apply`, this allows applying migrations on all connected databases in one go
- cli-migrations: add config v3 image
- docs: add Hasura v2 upgrade guide (#1030)
## v2.0.0-alpha.6

View File

@ -7,69 +7,67 @@
Auto-apply migrations/metadata when the server starts
=====================================================
`coming soon`
.. contents:: Table of contents
:backlinks: none
:depth: 1
:local:
.. .. contents:: Table of contents
.. :backlinks: none
.. :depth: 1
.. :local:
**cli-migrations** image
------------------------
.. **cli-migrations** image
.. ------------------------
Hasura ships a special Docker image which can be used to
automatically apply migrations/metadata when the server starts:
.. Hasura ships a special Docker image which can be used to
.. automatically apply migrations/metadata when the server starts:
.. code-block:: bash
.. .. code-block:: bash
hasura/graphql-engine:<version>.cli-migrations-v3
.. hasura/graphql-engine:<version>.cli-migrations-v2
This container image includes the Hasura CLI at ``/bin/hasura-cli`` and can be
used for running any other CI/CD scripts in your workflow.
.. This container image includes the Hasura CLI at ``/bin/hasura-cli`` and can be
.. used for running any other CI/CD scripts in your workflow.
.. note::
.. .. note::
For ``config v2``, see :ref:`auto_apply_migrations_v2`.
.. For ``config v1``, see :ref:`auto_apply_migrations_v1`.
Applying migrations
-------------------
.. Applying migrations
.. -------------------
The ``migrations`` and ``metadata`` directories created by the Hasura CLI in a
Hasura project can be mounted at the ``/hasura-migrations`` and ``/hasura-metadata``
path of this Docker container and the container's entry point script will apply the
migrations and metadata before starting the server. If no directory is mounted at
the designated paths, the server will start ignoring the migrations and/or metadata.
.. The ``migrations`` and ``metadata`` directories created by the Hasura CLI in a
.. Hasura project can be mounted at the ``/hasura-migrations`` and ``/hasura-metadata``
.. path of this Docker container and the container's entry point script will apply the
.. migrations and metadata before starting the server. If no directory is mounted at
.. the designated paths, the server will start ignoring the migrations and/or metadata.
If you want to mount the migrations/metadata directories at some location other
than the above, set the following environment variables:
.. If you want to mount the migrations/metadata directories at some location other
.. than the above, set the following environment variables:
.. code-block:: bash
.. .. code-block:: bash
HASURA_GRAPHQL_MIGRATIONS_DIR=/custom-path-for-migrations
HASURA_GRAPHQL_METADATA_DIR=/custom-path-for-metadata
.. HASURA_GRAPHQL_MIGRATIONS_DIR=/custom-path-for-migrations
.. HASURA_GRAPHQL_METADATA_DIR=/custom-path-for-metadata
Once the migrations and metadata are applied, the container resumes operation as
a normal Hasura GraphQL engine server.
.. Once the migrations and metadata are applied, the container resumes operation as
.. a normal Hasura GraphQL engine server.
Example:
.. Example:
.. code-block:: bash
.. .. code-block:: bash
.. # Start Hasura after applying the migrations and metadata present in the Hasura project
.. docker run -p 8080:8080 \
.. -v /home/me/my-project/migrations:/hasura-migrations \
.. -v /home/me/my-project/metadata:/hasura-metadata \
.. -e HASURA_GRAPHQL_DATABASE_URL=postgres://postgres:@postgres:5432/postgres \
.. hasura/graphql-engine:v1.2.0.cli-migrations-v2
# Start Hasura after applying the migrations and metadata present in the Hasura project
docker run -p 8080:8080 \
-v /home/me/my-project/migrations:/hasura-migrations \
-v /home/me/my-project/metadata:/hasura-metadata \
-e HASURA_GRAPHQL_DATABASE_URL=postgres://postgres:@postgres:5432/postgres \
hasura/graphql-engine:v2.0.0-alpha.7.cli-migrations-v3
.. .. _auto_apply_metadata:
.. _auto_apply_metadata:
.. Applying only metadata
.. ----------------------
Applying only metadata
----------------------
.. If you're managing migrations with a different tool and want to use this image
.. to apply only the metadata, mount the ``metadata`` directory of your Hasura project
.. at the ``/hasura-metadata`` path of this Docker container the containers entry point
.. script will apply the metadata before starting the server.
If you're managing migrations with a different tool and want to use this image
to apply only the metadata, mount the ``metadata`` directory of your Hasura project
at the ``/hasura-metadata`` path of this Docker container the containers entry point
script will apply the metadata before starting the server.

View File

@ -20,5 +20,34 @@ test-cli-migrations-v2:
cd v2/test
./test.sh
.PHONY: build-cli-migrations-v3
.ONESHELL:
build-cli-migrations-v3:
cd v3
./build.sh $(SERVER_BUILD_OUTPUT) $(CLI_BUILD_OUTPUT) $(BUILD_OUTPUT)
.PHONY: test-cli-migrations-v3
.ONESHELL:
test-cli-migrations-v3:
cd v3/test
./test.sh
.ONESHELL:
prepare-local-env:
# works on *nix systems
MAKEFILE_DIR=$(shell pwd)
mkdir /tmp/build
cd /tmp/build
mkdir _cli_migrations_output
# get server image and save it
LATEST_RELEASE=$(shell curl --silent "https://api.github.com/repos/hasura/graphql-engine/releases" | jq '.[0]' | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
mkdir _server_output && cd _server_output && docker save -o image.tar hasura/graphql-engine:$$LATEST_RELEASE && cd -
mkdir -p _cli_output/binaries && cd _cli_output/binaries && curl -LO https://github.com/hasura/graphql-engine/releases/download/$$LATEST_RELEASE/cli-hasura-linux-amd64 && cd -
# edit makefile to use /tmp/build as BUILD_DIR
cd $$MAKEFILE_DIR && sed -i 's/BUILD_DIR ?= \/build/BUILD_DIR ?= \/tmp\/build/' Makefile
reset-local-env:
sed -i 's/BUILD_DIR ?= \/tmp\/build/BUILD_DIR ?= \/build/' Makefile
.PHONY: all
all: build-cli-migrations-v2 test-cli-migrations-v2
all: build-cli-migrations-v2 test-cli-migrations-v2 build-cli-migrations-v3 test-cli-migrations-v3

View File

@ -1 +1,3 @@
[]
- table:
schema: public
name: test

View File

@ -27,6 +27,6 @@ wait_for_server
# export metadata and run diff with validation/metadata.json
docker run --network container:graphql-engine appropriate/curl -s -f -d'{"type" : "export_metadata", "args" : {} }' localhost:8080/v1/query | jq -j '.' | diff validation/metadata.json -
# get list of migrations applied from graphql-engine server
# docker run --network container:graphql-engine appropriate/curl -s -f -d'{"type" : "run_sql", "args" : {"sql": "select * from hdb_catalog.schema_migrations"} }' localhost:8080/v1/query | jq -j '.' | diff validation/schema_migrations.json -
docker run --network container:graphql-engine appropriate/curl -s -f -d'{"type" : "run_sql", "args" : {"sql": "select * from hdb_catalog.schema_migrations"} }' localhost:8080/v1/query | jq -j '.' | diff validation/schema_migrations.json -
# delete postgres and graphql-engine
docker-compose down -v

View File

@ -4,7 +4,14 @@
{
"name": "default",
"kind": "postgres",
"tables": [],
"tables": [
{
"table": {
"schema": "public",
"name": "test"
}
}
],
"configuration": {
"connection_info": {
"database_url": "postgres://postgres:postgrespassword@postgres:5432/postgres",

2
scripts/cli-migrations/v3/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
cli-hasura-linux-amd64
manifest.yaml

View File

@ -0,0 +1,22 @@
ARG SERVER_IMAGE_TAG
FROM hasura/graphql-engine:${SERVER_IMAGE_TAG}
RUN apt-get update && apt-get install -y netcat
# set an env var to let the cli know that
# update notification is disabled
ENV HASURA_GRAPHQL_SHOW_UPDATE_NOTIFICATION=false
COPY docker-entrypoint.sh /bin/
COPY cli-hasura-linux-amd64 /bin/hasura-cli
RUN chmod +x /bin/hasura-cli
# set an env var to let the cli know that
# it is running in server environment
ENV HASURA_GRAPHQL_CLI_ENVIRONMENT=server-on-docker
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["graphql-engine", "serve"]

View File

@ -0,0 +1,111 @@
# CLI Migrations
This docker image provides a method to run migrations and metadata at docker entrypoint.
A temporary server is booted, with the migrations API allowed, securely through localhost.
Once migrations and metadata have been applied, the server will reboot in a secure mode for inbound graphql usage.
See [./docker-entrypoint.sh](docker-entrypoint.sh)
- [CLI Migrations](#cli-migrations)
- [Examples](#examples)
- [Local](#local)
- [Heroku](#heroku)
- [Provision](#provision)
- [Deploy](#deploy)
- [Configuration](#configuration)
- [Migrations Directory (Optional)](#migrations-directory-optional)
- [Metadata Directory (Optional)](#metadata-directory-optional)
- [Database (One of required)](#database-one-of-them-required)
- [GraphQL Server (Optional)](#graphql-server-optional)
## Examples
It is used in a docker file as:
```dockerfile
FROM hasura/graphql-engine:<version>.cli-migrations-v3
CMD graphql-engine \
--metadata-database-url $METADATA_DATABASE_URL \
serve \
--server-port $PORT \
--enable-console
```
### Local
This is covered in the documentation here: https://hasura.io/docs/latest/graphql/core/migrations/auto-apply-migrations.html
The below [Configuration](#configuration) will also be applicable.
### Heroku
Using a docker build on heroku the manifest (`heroku.yml`) can look like:
```yaml
setup:
addons:
- plan: heroku-postgresql
as: DATABASE
config:
HASURA_METADATA_DATABASE_URL: DATABASE_URL
build:
docker:
web: Dockerfile
```
This allows you to provision and migrate a database entirely without intervention.
#### Provision
Setup the app, with addons and the setup steps defined in the heroku.yml
```bash
heroku create heroku-migration-tester --manifest
```
#### Deploy
```bash
export HEROKU_GIT_REMOTE=https://git.heroku.com/heroku-migration-tester.git
git init && git add .
git commit -m "first commit"
git remote add heroku HEROKU_GIT_REMOTE
git push heroku master
```
## Configuration
You may set the following environment variables to configure the way this image is run.
### Migrations Directory (Optional)
Migrations are either mounted or built into the image.
If it has been stored in a directory other than the default then it can be configured using the following:
- `HASURA_GRAPHQL_MIGRATIONS_DIR` (default=`/hasura-migrations`)
A path to the migrations directory.
### Metadata Directory (Optional)
Metadata are either mounted or built into the image.
If it has been stored in a directory other than the default then it can be configured using the following:
- `HASURA_GRAPHQL_METADATA_DIR` (default=`/hasura-metadata`)
A path to the metadata directory.
### GraphQL Server (Optional)
Optional configuration for the server which boots during migrations.
- `HASURA_GRAPHQL_MIGRATIONS_SERVER_PORT` (default=`9691`)
Specify the port running the graphql server during execution of the migration script.
It is advised that you do not specify a PORT that may be open e.g. 80/443 and the default should rarely require changing.
- `HASURA_GRAPHQL_MIGRATIONS_SERVER_TIMEOUT` (default=`30s`)
Specify the server timeout threshold.

View File

@ -0,0 +1,20 @@
#!/usr/bin/env bash
set -evo pipefail
SERVER_BUILD_OUTPUT="$1"
CLI_BUILD_OUTPUT="$2"
BUILD_OUTPUT="$3"
CLI_MIGRATIONS_IMAGE="cli-migrations-v3"
SERVER_IMAGE=$(docker load -i "${SERVER_BUILD_OUTPUT}/image.tar" | grep "^Loaded image: " | sed "s/Loaded image: //g")
SERVER_IMAGE_TAG=$(echo "$SERVER_IMAGE" | sed "s/.*:\(.*\)$/\1/")
echo "SERVER_IMAGE is ${SERVER_IMAGE}"
echo "SERVER_IMAGE_TAG is ${SERVER_IMAGE_TAG}"
BINARY=${CLI_BUILD_OUTPUT}/binaries/cli-hasura-linux-amd64
cp ${BINARY} .
docker build -t "${CLI_MIGRATIONS_IMAGE}" . --build-arg SERVER_IMAGE_TAG=$SERVER_IMAGE_TAG
docker save -o "${BUILD_OUTPUT}/v3.tar" "${CLI_MIGRATIONS_IMAGE}"

View File

@ -0,0 +1,101 @@
#!/bin/sh
set -e
log() {
TIMESTAMP=$(date -u "+%Y-%m-%dT%H:%M:%S.000+0000")
LOGKIND=$1
MESSAGE=$2
echo "{\"timestamp\":\"$TIMESTAMP\",\"level\":\"info\",\"type\":\"startup\",\"detail\":{\"kind\":\"$LOGKIND\",\"info\":\"$MESSAGE\"}}"
}
DEFAULT_MIGRATIONS_DIR="/hasura-migrations"
DEFAULT_METADATA_DIR="/hasura-metadata"
TEMP_PROJECT_DIR="/tmp/hasura-project"
# Use 9691 port for running temporary instance.
# In case 9691 is occupied (according to docker networking), then this will fail.
# override with another port in that case
# TODO: Find a proper random port
if [ -z ${HASURA_GRAPHQL_MIGRATIONS_SERVER_PORT+x} ]; then
log "migrations-startup" "migrations server port env var is not set, defaulting to 9691"
HASURA_GRAPHQL_MIGRATIONS_SERVER_PORT=9691
fi
if [ -z ${HASURA_GRAPHQL_MIGRATIONS_SERVER_TIMEOUT+x} ]; then
log "migrations-startup" "server timeout is not set, defaulting to 30 seconds"
HASURA_GRAPHQL_MIGRATIONS_SERVER_TIMEOUT=30
fi
# wait for a port to be ready
wait_for_port() {
local PORT=$1
log "migrations-startup" "waiting $HASURA_GRAPHQL_MIGRATIONS_SERVER_TIMEOUT for $PORT to be ready"
for i in `seq 1 $HASURA_GRAPHQL_MIGRATIONS_SERVER_TIMEOUT`;
do
nc -z localhost $PORT > /dev/null 2>&1 && log "migrations-startup" "port $PORT is ready" && return
sleep 1
done
log "migrations-startup" "failed waiting for $PORT, try increasing HASURA_GRAPHQL_MIGRATIONS_SERVER_TIMEOUT (default: 30)" && exit 1
}
log "migrations-startup" "starting graphql engine temporarily on port $HASURA_GRAPHQL_MIGRATIONS_SERVER_PORT"
# start graphql engine with metadata api enabled
graphql-engine serve --enabled-apis="metadata" \
--server-port=${HASURA_GRAPHQL_MIGRATIONS_SERVER_PORT} &
# store the pid to kill it later
PID=$!
# wait for port to be ready
wait_for_port $HASURA_GRAPHQL_MIGRATIONS_SERVER_PORT
# check if migration directory is set, default otherwise
if [ -z ${HASURA_GRAPHQL_MIGRATIONS_DIR+x} ]; then
log "migrations-startup" "env var HASURA_GRAPHQL_MIGRATIONS_DIR is not set, defaulting to $DEFAULT_MIGRATIONS_DIR"
HASURA_GRAPHQL_MIGRATIONS_DIR="$DEFAULT_MIGRATIONS_DIR"
fi
# check if metadata directory is set, default otherwise
if [ -z ${HASURA_GRAPHQL_METADATA_DIR+x} ]; then
log "migrations-startup" "env var HASURA_GRAPHQL_METADATA_DIR is not set, defaulting to $DEFAULT_METADATA_DIR"
HASURA_GRAPHQL_METADATA_DIR="$DEFAULT_METADATA_DIR"
fi
# apply metadata if the directory exist
if [ -d "$HASURA_GRAPHQL_METADATA_DIR" ]; then
rm -rf "TEMP_PROJECT_DIR"
log "migrations-apply" "applying metadata from $HASURA_GRAPHQL_METADATA_DIR"
mkdir -p "$TEMP_PROJECT_DIR"
cp -a "$HASURA_GRAPHQL_METADATA_DIR/." "$TEMP_PROJECT_DIR/metadata/"
cd "$TEMP_PROJECT_DIR"
echo "version: 3" > config.yaml
echo "endpoint: http://localhost:$HASURA_GRAPHQL_MIGRATIONS_SERVER_PORT" >> config.yaml
echo "metadata_directory: metadata" >> config.yaml
hasura-cli metadata apply
else
log "migrations-apply" "directory $HASURA_GRAPHQL_METADATA_DIR does not exist, skipping metadata"
fi
# apply migrations if the directory exist
if [ -d "$HASURA_GRAPHQL_MIGRATIONS_DIR" ]; then
log "migrations-apply" "applying migrations from $HASURA_GRAPHQL_MIGRATIONS_DIR"
mkdir -p "$TEMP_PROJECT_DIR"
cp -a "$HASURA_GRAPHQL_MIGRATIONS_DIR/." "$TEMP_PROJECT_DIR/migrations/"
cd "$TEMP_PROJECT_DIR"
echo "version: 3" > config.yaml
echo "endpoint: http://localhost:$HASURA_GRAPHQL_MIGRATIONS_SERVER_PORT" >> config.yaml
hasura-cli migrate apply --all-databases
log "migrations-apply" "reloading metadata"
hasura-cli metadata reload
else
log "migrations-apply" "directory $HASURA_GRAPHQL_MIGRATIONS_DIR does not exist, skipping migrations"
fi
# kill graphql engine that we started earlier
log "migrations-shutdown" "killing temporary server"
kill $PID
# pass control to CMD
log "migrations-shutdown" "graphql-engine will now start in normal mode"
exec "$@"

View File

@ -0,0 +1,19 @@
version: '3.6'
services:
postgres:
image: postgres:12
restart: always
environment:
POSTGRES_PASSWORD: postgrespassword
graphql-engine:
container_name: graphql-engine
image: cli-migrations-v3
ports:
- "8080:8080"
depends_on:
- "postgres"
restart: always
environment:
HASURA_GRAPHQL_DATABASE_URL: postgres://postgres:postgrespassword@postgres:5432/postgres
HASURA_GRAPHQL_ENABLE_CONSOLE: "true" # set to "false" to disable console
HASURA_GRAPHQL_ENABLED_LOG_TYPES: startup, http-log, webhook-log, websocket-log, query-log

View File

@ -0,0 +1,2 @@

View File

@ -0,0 +1,6 @@
actions: []
custom_types:
enums: []
input_objects: []
objects: []
scalars: []

View File

@ -0,0 +1 @@
[]

View File

@ -0,0 +1 @@
[]

View File

@ -0,0 +1,12 @@
- name: default
kind: postgres
configuration:
connection_info:
database_url:
from_env: HASURA_GRAPHQL_DATABASE_URL
pool_settings:
idle_timeout: 180
max_connections: 50
retries: 1
tables: "!include default/tables/tables.yaml"
functions: "!include default/functions/functions.yaml"

View File

@ -0,0 +1,3 @@
table:
name: test
schema: public

View File

@ -0,0 +1 @@
- "!include public_test.yaml"

View File

@ -0,0 +1 @@
[]

View File

@ -0,0 +1 @@
[]

View File

@ -0,0 +1 @@
[]

View File

@ -0,0 +1 @@
[]

View File

@ -0,0 +1 @@
version: 3

View File

@ -0,0 +1 @@
DROP TABLE "public"."test";

View File

@ -0,0 +1 @@
CREATE TABLE "public"."test" ("id" serial NOT NULL, "created_at" timestamptz NOT NULL DEFAULT now(), PRIMARY KEY ("id") );

View File

@ -0,0 +1,32 @@
#!/usr/bin/env bash
set -evo pipefail
IFS=$'\n\t'
ROOT="$(readlink -f ${BASH_SOURCE[0]%/*}/../../)"
wait_for_server() {
echo "waiting for server"
for _ in $(seq 1 60);
do
docker run --network container:graphql-engine appropriate/curl http://127.0.0.1:8080/v1/version && return
echo -n .
sleep 1
done
echo "Failed waiting for server" && exit 1
}
# start postgres
docker-compose up --no-start graphql-engine
# copy migrations directory to /hasura-migrations
docker cp migrations/. graphql-engine:/hasura-migrations
# copy metadata directory to /hasura-metadata
docker cp metadata/. graphql-engine:/hasura-metadata
# start graphql-engine
docker-compose up -d --no-recreate graphql-engine
wait_for_server
# export metadata and run diff with validation/metadata.json
docker run --network container:graphql-engine appropriate/curl -s -f -d'{"type" : "export_metadata", "args" : {} }' localhost:8080/v1/metadata | jq -j '.' | diff validation/metadata.json -
# get list of migrations applied from graphql-engine server
docker run --network container:graphql-engine appropriate/curl -s -f -d'{"type" : "get_catalog_state", "args" : {} }' localhost:8080/v1/metadata | jq .cli_state | diff validation/catalog_cli_state.json -
# delete postgres and graphql-engine
docker-compose down -v

View File

@ -0,0 +1,10 @@
{
"settings": {
"migration_mode": "true"
},
"migrations": {
"default": {
"1616826329751": false
}
}
}

View File

@ -0,0 +1,29 @@
{
"version": 3,
"sources": [
{
"name": "default",
"kind": "postgres",
"tables": [
{
"table": {
"schema": "public",
"name": "test"
}
}
],
"configuration": {
"connection_info": {
"database_url": {
"from_env": "HASURA_GRAPHQL_DATABASE_URL"
},
"pool_settings": {
"retries": 1,
"idle_timeout": 180,
"max_connections": 50
}
}
}
}
]
}