222 lines
5.8 KiB
Lua
222 lines
5.8 KiB
Lua
local log = require "kong.cmd.utils.log"
|
|
|
|
|
|
local MIGRATIONS_MUTEX_KEY = "migrations"
|
|
local NOT_LEADER_MSG = "aborted: another node is performing database changes"
|
|
local NEEDS_BOOTSTRAP_MSG = "Database needs bootstrapping or is older than Kong 1.0.\n\n" ..
|
|
"To start a new installation from scratch, run 'kong migrations bootstrap'.\n\n" ..
|
|
"To migrate from a version older than 1.0, migrated to Kong 1.5.0 first. \n" ..
|
|
"If you still have 'apis' entities, you can convert them to Routes and Services\n" ..
|
|
"using the 'kong migrations migrate-apis' command in Kong 1.5.0.\n\n"
|
|
|
|
|
|
local function check_state(schema_state)
|
|
if not schema_state:is_up_to_date() then
|
|
if schema_state.needs_bootstrap then
|
|
error(NEEDS_BOOTSTRAP_MSG)
|
|
end
|
|
|
|
if schema_state.new_migrations then
|
|
error("New migrations available; run 'kong migrations up' to proceed")
|
|
end
|
|
end
|
|
end
|
|
|
|
local function bootstrap(schema_state, db, ttl)
|
|
if schema_state.needs_bootstrap then
|
|
log("Bootstrapping database...")
|
|
assert(db:schema_bootstrap())
|
|
|
|
else
|
|
log("Database already bootstrapped")
|
|
return
|
|
end
|
|
|
|
local opts = {
|
|
ttl = ttl,
|
|
no_wait = true, -- exit the mutex if another node acquired it
|
|
}
|
|
|
|
local ok, err = db:cluster_mutex(MIGRATIONS_MUTEX_KEY, opts, function()
|
|
assert(db:run_migrations(schema_state.new_migrations, {
|
|
run_up = true,
|
|
run_teardown = true,
|
|
}))
|
|
log("Database is up-to-date")
|
|
end)
|
|
if err then
|
|
error(err)
|
|
end
|
|
|
|
if not ok then
|
|
log(NOT_LEADER_MSG)
|
|
end
|
|
end
|
|
|
|
|
|
local function up(schema_state, db, opts)
|
|
if schema_state.needs_bootstrap then
|
|
-- fresh install: must bootstrap (which will run migrations up)
|
|
error("Cannot run migrations: " .. NEEDS_BOOTSTRAP_MSG)
|
|
end
|
|
|
|
-- see #6105 for background, this is a workaround that gives a better
|
|
-- error message (one w/o the long stacktrace) when the pending
|
|
-- migration checks failed
|
|
if not opts.force and schema_state.pending_migrations then
|
|
error("Database has pending migrations; run 'kong migrations finish'")
|
|
end
|
|
|
|
local ok, err = db:cluster_mutex(MIGRATIONS_MUTEX_KEY, opts, function()
|
|
schema_state = assert(db:schema_state())
|
|
|
|
if not opts.force and schema_state.pending_migrations then
|
|
error("Database has pending migrations; run 'kong migrations finish'")
|
|
end
|
|
|
|
if opts.force and schema_state.executed_migrations then
|
|
log.debug("forcing re-execution of these migrations:\n%s",
|
|
schema_state.executed_migrations)
|
|
|
|
assert(db:run_migrations(schema_state.executed_migrations, {
|
|
run_up = true,
|
|
run_teardown = true,
|
|
skip_teardown_migrations = schema_state.pending_migrations
|
|
}))
|
|
|
|
schema_state = assert(db:schema_state())
|
|
if schema_state.pending_migrations then
|
|
log("\nDatabase has pending migrations; run 'kong migrations finish' when ready")
|
|
return
|
|
end
|
|
end
|
|
|
|
if not schema_state.new_migrations then
|
|
if not opts.force then
|
|
log("Database is already up-to-date")
|
|
end
|
|
|
|
return
|
|
end
|
|
|
|
log.debug("migrations to run:\n%s", schema_state.new_migrations)
|
|
|
|
assert(db:run_migrations(schema_state.new_migrations, {
|
|
run_up = true,
|
|
}))
|
|
|
|
schema_state = assert(db:schema_state())
|
|
if schema_state.pending_migrations then
|
|
log("\nDatabase has pending migrations; run 'kong migrations finish' when ready")
|
|
return
|
|
end
|
|
end)
|
|
if err then
|
|
error(err)
|
|
end
|
|
|
|
if not ok then
|
|
log(NOT_LEADER_MSG)
|
|
end
|
|
|
|
return ok
|
|
end
|
|
|
|
|
|
local function finish(schema_state, db, opts)
|
|
if schema_state.needs_bootstrap then
|
|
error("Cannot run migrations: " .. NEEDS_BOOTSTRAP_MSG)
|
|
end
|
|
|
|
opts.no_wait = true -- exit the mutex if another node acquired it
|
|
|
|
local ok, err = db:cluster_mutex(MIGRATIONS_MUTEX_KEY, opts, function()
|
|
local schema_state = assert(db:schema_state())
|
|
|
|
if opts.force and schema_state.executed_migrations then
|
|
assert(db:run_migrations(schema_state.executed_migrations, {
|
|
run_up = true,
|
|
run_teardown = true,
|
|
}))
|
|
|
|
schema_state = assert(db:schema_state())
|
|
end
|
|
|
|
if schema_state.pending_migrations then
|
|
log.debug("pending migrations to finish:\n%s",
|
|
schema_state.pending_migrations)
|
|
|
|
assert(db:run_migrations(schema_state.pending_migrations, {
|
|
run_teardown = true,
|
|
}))
|
|
|
|
schema_state = assert(db:schema_state())
|
|
end
|
|
|
|
if schema_state.new_migrations then
|
|
log("\nNew migrations available; run 'kong migrations up' to proceed")
|
|
return
|
|
end
|
|
|
|
if not opts.force and not schema_state.pending_migrations then
|
|
log("No pending migrations to finish")
|
|
end
|
|
|
|
return
|
|
end)
|
|
if err then
|
|
error(err)
|
|
end
|
|
|
|
if not ok then
|
|
log(NOT_LEADER_MSG)
|
|
end
|
|
end
|
|
|
|
|
|
local function reset(schema_state, db, ttl)
|
|
if schema_state.needs_bootstrap then
|
|
log("Database not bootstrapped, nothing to reset")
|
|
return false
|
|
end
|
|
|
|
local opts = {
|
|
ttl = ttl,
|
|
no_wait = true,
|
|
no_cleanup = true,
|
|
}
|
|
|
|
local ok, err = db:cluster_mutex(MIGRATIONS_MUTEX_KEY, opts, function()
|
|
log("Resetting database...")
|
|
assert(db:schema_reset())
|
|
log("Database successfully reset")
|
|
end)
|
|
if err then
|
|
-- failed to acquire locks - maybe locks table was dropped?
|
|
log.error(err .. " - retrying without cluster lock")
|
|
log("Resetting database...")
|
|
-- ROLLBACK in order to solve this error
|
|
-- ERROR: current transaction is aborted, commands ignored until end of transaction block
|
|
assert(db.connector:query("ROLLBACK;"))
|
|
assert(db:schema_reset())
|
|
log("Database successfully reset")
|
|
return true
|
|
end
|
|
|
|
if not ok then
|
|
log(NOT_LEADER_MSG)
|
|
return false
|
|
end
|
|
return true
|
|
end
|
|
|
|
|
|
return {
|
|
up = up,
|
|
reset = reset,
|
|
finish = finish,
|
|
bootstrap = bootstrap,
|
|
check_state = check_state,
|
|
NEEDS_BOOTSTRAP_MSG = NEEDS_BOOTSTRAP_MSG,
|
|
}
|