mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-03-11 02:12:21 -05:00
fix: enable maintenance mode only if there is an upgrade to perform (#7129)
refs #7125 - create isDatabaseOutOfDate fn for initial migration update checks - only set maintenance.enabled to true if migration needs to happen
This commit is contained in:
parent
d08926c347
commit
417b9b6b7c
4 changed files with 131 additions and 82 deletions
|
@ -11,7 +11,7 @@ var Promise = require('bluebird'),
|
|||
|
||||
updateDatabaseSchema,
|
||||
migrateToDatabaseVersion,
|
||||
update, logger;
|
||||
execute, logger, isDatabaseOutOfDate;
|
||||
|
||||
// @TODO: remove me asap!
|
||||
logger = {
|
||||
|
@ -77,7 +77,7 @@ migrateToDatabaseVersion = function migrateToDatabaseVersion(version, logger, mo
|
|||
* ## Update
|
||||
* Does a backup, then updates the database and fixtures
|
||||
*/
|
||||
update = function update(options) {
|
||||
execute = function execute(options) {
|
||||
options = options || {};
|
||||
|
||||
var fromVersion = options.fromVersion,
|
||||
|
@ -90,40 +90,51 @@ update = function update(options) {
|
|||
}
|
||||
};
|
||||
|
||||
fromVersion = forceMigration ? versioning.canMigrateFromVersion : fromVersion;
|
||||
|
||||
// Figure out which versions we're updating through.
|
||||
// This shouldn't include the from/current version (which we're already on)
|
||||
versionsToUpdate = versioning.getMigrationVersions(fromVersion, toVersion).slice(1);
|
||||
|
||||
return backup(logger)
|
||||
.then(function () {
|
||||
return Promise.mapSeries(versionsToUpdate, function (versionToUpdate) {
|
||||
return migrateToDatabaseVersion(versionToUpdate, logger, modelOptions);
|
||||
});
|
||||
})
|
||||
.then(function () {
|
||||
logger.info('Finished!');
|
||||
});
|
||||
};
|
||||
|
||||
isDatabaseOutOfDate = function isDatabaseOutOfDate(options) {
|
||||
options = options || {};
|
||||
|
||||
var fromVersion = options.fromVersion,
|
||||
toVersion = options.toVersion,
|
||||
forceMigration = options.forceMigration;
|
||||
|
||||
// CASE: current database version is lower then we support
|
||||
if (fromVersion < versioning.canMigrateFromVersion) {
|
||||
return Promise.reject(new errors.DatabaseVersion(
|
||||
return {error: new errors.DatabaseVersion(
|
||||
i18n.t('errors.data.versioning.index.cannotMigrate.error'),
|
||||
i18n.t('errors.data.versioning.index.cannotMigrate.context'),
|
||||
i18n.t('common.seeLinkForInstructions', {link: 'http://support.ghost.org/how-to-upgrade/'})
|
||||
));
|
||||
)};
|
||||
}
|
||||
// CASE: the database exists but is out of date
|
||||
else if (fromVersion < toVersion || forceMigration) {
|
||||
fromVersion = forceMigration ? versioning.canMigrateFromVersion : fromVersion;
|
||||
|
||||
// Figure out which versions we're updating through.
|
||||
// This shouldn't include the from/current version (which we're already on)
|
||||
versionsToUpdate = versioning.getMigrationVersions(fromVersion, toVersion).slice(1);
|
||||
|
||||
return backup(logger)
|
||||
.then(function () {
|
||||
return Promise.mapSeries(versionsToUpdate, function (versionToUpdate) {
|
||||
return migrateToDatabaseVersion(versionToUpdate, logger, modelOptions);
|
||||
});
|
||||
})
|
||||
.then(function () {
|
||||
logger.info('Finished!');
|
||||
});
|
||||
return {migrate: true};
|
||||
}
|
||||
// CASE: database is up-to-date
|
||||
else if (fromVersion === toVersion) {
|
||||
return Promise.resolve();
|
||||
return {migrate: false};
|
||||
}
|
||||
// CASE: we don't understand the version
|
||||
else {
|
||||
return Promise.reject(new errors.DatabaseVersion(i18n.t('errors.data.versioning.index.dbVersionNotRecognized')));
|
||||
return {error: new errors.DatabaseVersion(i18n.t('errors.data.versioning.index.dbVersionNotRecognized'))};
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = update;
|
||||
exports.execute = execute;
|
||||
exports.isDatabaseOutOfDate = isDatabaseOutOfDate;
|
||||
|
|
|
@ -69,18 +69,28 @@ function init(options) {
|
|||
}).then(function () {
|
||||
return versioning.getDatabaseVersion()
|
||||
.then(function (currentVersion) {
|
||||
var maintenanceState = config.maintenance.enabled || false;
|
||||
config.maintenance.enabled = true;
|
||||
|
||||
migrations.update({
|
||||
var response = migrations.update.isDatabaseOutOfDate({
|
||||
fromVersion: currentVersion,
|
||||
toVersion: versioning.getNewestDatabaseVersion(),
|
||||
forceMigration: process.env.FORCE_MIGRATION
|
||||
}).then(function () {
|
||||
config.maintenance.enabled = maintenanceState;
|
||||
}).catch(function (err) {
|
||||
errors.logErrorAndExit(err, err.context, err.help);
|
||||
});
|
||||
}), maintenanceState;
|
||||
|
||||
if (response.migrate === true) {
|
||||
maintenanceState = config.maintenance.enabled || false;
|
||||
config.maintenance.enabled = true;
|
||||
|
||||
migrations.update.execute({
|
||||
fromVersion: currentVersion,
|
||||
toVersion: versioning.getNewestDatabaseVersion(),
|
||||
forceMigration: process.env.FORCE_MIGRATION
|
||||
}).then(function () {
|
||||
config.maintenance.enabled = maintenanceState;
|
||||
}).catch(function (err) {
|
||||
errors.logErrorAndExit(err, err.context, err.help);
|
||||
});
|
||||
} else if (response.error) {
|
||||
return Promise.reject(response.error);
|
||||
}
|
||||
})
|
||||
.catch(function (err) {
|
||||
if (err instanceof errors.DatabaseNotPopulated) {
|
||||
|
|
|
@ -6,7 +6,7 @@ var should = require('should'),
|
|||
crypto = require('crypto'),
|
||||
fs = require('fs'),
|
||||
|
||||
// Stuff we are testing
|
||||
// Stuff we are testing
|
||||
db = require('../../server/data/db'),
|
||||
errors = require('../../server/errors'),
|
||||
models = require('../../server/models'),
|
||||
|
@ -204,6 +204,45 @@ describe('Migrations', function () {
|
|||
});
|
||||
});
|
||||
|
||||
describe('isDatabaseOutOfDate', function () {
|
||||
var updateDatabaseSchemaStub, updateDatabaseSchemaReset, versionsSpy;
|
||||
|
||||
beforeEach(function () {
|
||||
versionsSpy = sandbox.spy(schema.versioning, 'getMigrationVersions');
|
||||
|
||||
// For these tests, stub out the actual update task
|
||||
updateDatabaseSchemaStub = sandbox.stub().returns(new Promise.resolve());
|
||||
updateDatabaseSchemaReset = update.__set__('updateDatabaseSchema', updateDatabaseSchemaStub);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
updateDatabaseSchemaReset();
|
||||
});
|
||||
|
||||
it('should throw error if versions are too old', function () {
|
||||
var response = update.isDatabaseOutOfDate({fromVersion: '000', toVersion: '002'});
|
||||
updateDatabaseSchemaStub.calledOnce.should.be.false();
|
||||
(response.error instanceof errors.DatabaseVersion).should.eql(true);
|
||||
});
|
||||
|
||||
it('should just return if versions are the same', function () {
|
||||
var migrateToDatabaseVersionStub = sandbox.stub().returns(new Promise.resolve()),
|
||||
migrateToDatabaseVersionReset = update.__set__('migrateToDatabaseVersion', migrateToDatabaseVersionStub),
|
||||
response = update.isDatabaseOutOfDate({fromVersion: '004', toVersion: '004'});
|
||||
|
||||
response.migrate.should.eql(false);
|
||||
versionsSpy.calledOnce.should.be.false();
|
||||
migrateToDatabaseVersionStub.callCount.should.eql(0);
|
||||
migrateToDatabaseVersionReset();
|
||||
});
|
||||
|
||||
it('should throw an error if the database version is higher than the default', function () {
|
||||
var response = update.isDatabaseOutOfDate({fromVersion: '010', toVersion: '004'});
|
||||
updateDatabaseSchemaStub.calledOnce.should.be.false();
|
||||
(response.error instanceof errors.DatabaseVersion).should.eql(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Update', function () {
|
||||
describe('Update function', function () {
|
||||
var resetBackup, backupStub, fixturesStub, setDbStub, versionsSpy, tasksSpy, transactionStub, transaction;
|
||||
|
@ -252,7 +291,7 @@ describe('Migrations', function () {
|
|||
|
||||
it('should attempt to run the pre & post update tasks correctly', function (done) {
|
||||
// Execute
|
||||
update({fromVersion: '100', toVersion: '102'}).then(function () {
|
||||
update.execute({fromVersion: '100', toVersion: '102'}).then(function () {
|
||||
// getMigrationVersions should be called with the correct versions
|
||||
versionsSpy.calledOnce.should.be.true();
|
||||
versionsSpy.calledWith('100', '102').should.be.true();
|
||||
|
@ -288,21 +327,11 @@ describe('Migrations', function () {
|
|||
}).catch(done);
|
||||
});
|
||||
|
||||
it('should throw error if versions are too old', function (done) {
|
||||
update({fromVersion: '000', toVersion: '002'}).then(function () {
|
||||
done(new Error('expected database version too old error'));
|
||||
}).catch(function (err) {
|
||||
updateDatabaseSchemaStub.calledOnce.should.be.false();
|
||||
(err instanceof errors.DatabaseVersion).should.eql(true);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should upgrade from minimum version, if force migration is set', function (done) {
|
||||
var migrateToDatabaseVersionStub = sandbox.stub().returns(new Promise.resolve()),
|
||||
migrateToDatabaseVersionReset = update.__set__('migrateToDatabaseVersion', migrateToDatabaseVersionStub);
|
||||
|
||||
update({fromVersion: '005', toVersion: '006', forceMigration: true}).then(function () {
|
||||
update.execute({fromVersion: '005', toVersion: '006', forceMigration: true}).then(function () {
|
||||
// getMigrationVersions should be called with the correct versions
|
||||
versionsSpy.calledOnce.should.be.true();
|
||||
versionsSpy.calledWith('003', '006').should.be.true();
|
||||
|
@ -323,7 +352,7 @@ describe('Migrations', function () {
|
|||
var migrateToDatabaseVersionStub = sandbox.stub().returns(new Promise.resolve()),
|
||||
migrateToDatabaseVersionReset = update.__set__('migrateToDatabaseVersion', migrateToDatabaseVersionStub);
|
||||
|
||||
update({fromVersion: '004', toVersion: '005'}).then(function () {
|
||||
update.execute({fromVersion: '004', toVersion: '005'}).then(function () {
|
||||
versionsSpy.calledOnce.should.be.true();
|
||||
versionsSpy.calledWith('004', '005').should.be.true();
|
||||
versionsSpy.returned(['004', '005']).should.be.true();
|
||||
|
@ -341,7 +370,7 @@ describe('Migrations', function () {
|
|||
var migrateToDatabaseVersionStub = sandbox.stub().returns(new Promise.resolve()),
|
||||
migrateToDatabaseVersionReset = update.__set__('migrateToDatabaseVersion', migrateToDatabaseVersionStub);
|
||||
|
||||
update({fromVersion: '004', toVersion: '010'}).then(function () {
|
||||
update.execute({fromVersion: '004', toVersion: '010'}).then(function () {
|
||||
versionsSpy.calledOnce.should.be.true();
|
||||
versionsSpy.calledWith('004', '010').should.be.true();
|
||||
versionsSpy.returned(['004', '005', '006', '007', '008', '009', '010']).should.be.true();
|
||||
|
@ -356,24 +385,11 @@ describe('Migrations', function () {
|
|||
}).catch(done);
|
||||
});
|
||||
|
||||
it('should just return if versions are the same', function (done) {
|
||||
var migrateToDatabaseVersionStub = sandbox.stub().returns(new Promise.resolve()),
|
||||
migrateToDatabaseVersionReset = update.__set__('migrateToDatabaseVersion', migrateToDatabaseVersionStub);
|
||||
|
||||
update({fromVersion: '004', toVersion: '004'}).then(function () {
|
||||
versionsSpy.calledOnce.should.be.false();
|
||||
migrateToDatabaseVersionStub.callCount.should.eql(0);
|
||||
migrateToDatabaseVersionReset();
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('should do an UPDATE even if versions are the same, when FORCE_MIGRATION set', function (done) {
|
||||
var migrateToDatabaseVersionStub = sandbox.stub().returns(new Promise.resolve()),
|
||||
migrateToDatabaseVersionReset = update.__set__('migrateToDatabaseVersion', migrateToDatabaseVersionStub);
|
||||
|
||||
update({fromVersion: '004', toVersion: '004', forceMigration: true}).then(function () {
|
||||
update.execute({fromVersion: '004', toVersion: '004', forceMigration: true}).then(function () {
|
||||
versionsSpy.calledOnce.should.be.true();
|
||||
versionsSpy.calledWith('003', '004').should.be.true();
|
||||
versionsSpy.returned(['003', '004']).should.be.true();
|
||||
|
@ -385,16 +401,6 @@ describe('Migrations', function () {
|
|||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('should throw an error if the database version is higher than the default', function (done) {
|
||||
update({fromVersion: '010', toVersion: '004'}).then(function () {
|
||||
done(new Error('expected database version too old error'));
|
||||
}).catch(function (err) {
|
||||
updateDatabaseSchemaStub.calledOnce.should.be.false();
|
||||
(err instanceof errors.DatabaseVersion).should.eql(true);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Update to 004', function () {
|
||||
|
@ -407,7 +413,7 @@ describe('Migrations', function () {
|
|||
sequenceStub.returns(Promise.resolve([]));
|
||||
|
||||
// Execute
|
||||
update({fromVersion: '003', toVersion: '004'}).then(function () {
|
||||
update.execute({fromVersion: '003', toVersion: '004'}).then(function () {
|
||||
versionsSpy.calledOnce.should.be.true();
|
||||
versionsSpy.calledWith('003', '004').should.be.true();
|
||||
|
||||
|
@ -888,7 +894,7 @@ describe('Migrations', function () {
|
|||
sequenceStub.returns(Promise.resolve([]));
|
||||
|
||||
// Execute
|
||||
update({fromVersion: '004', toVersion: '005'}).then(function () {
|
||||
update.execute({fromVersion: '004', toVersion: '005'}).then(function () {
|
||||
versionsSpy.calledOnce.should.be.true();
|
||||
versionsSpy.calledWith('004', '005').should.be.true();
|
||||
versionsSpy.returned(['004', '005']).should.be.true();
|
||||
|
|
|
@ -51,8 +51,8 @@ describe('server bootstrap', function () {
|
|||
});
|
||||
|
||||
describe('migrations', function () {
|
||||
it('database does not exist', function (done) {
|
||||
sandbox.stub(migration, 'update').returns(Promise.resolve());
|
||||
it('database does not exist: expect database population', function (done) {
|
||||
sandbox.stub(migration.update, 'isDatabaseOutOfDate').returns({migrate:false});
|
||||
|
||||
sandbox.stub(versioning, 'getDatabaseVersion', function () {
|
||||
return Promise.reject();
|
||||
|
@ -61,7 +61,7 @@ describe('server bootstrap', function () {
|
|||
bootstrap()
|
||||
.then(function () {
|
||||
migration.populate.calledOnce.should.eql(true);
|
||||
migration.update.calledOnce.should.eql(false);
|
||||
migration.update.execute.calledOnce.should.eql(false);
|
||||
models.Settings.populateDefaults.callCount.should.eql(1);
|
||||
config.maintenance.enabled.should.eql(false);
|
||||
done();
|
||||
|
@ -71,11 +71,9 @@ describe('server bootstrap', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('database does exist', function (done) {
|
||||
sandbox.stub(migration, 'update', function () {
|
||||
config.maintenance.enabled.should.eql(true);
|
||||
return Promise.resolve();
|
||||
});
|
||||
it('database does exist: expect no update', function (done) {
|
||||
sandbox.stub(migration.update, 'isDatabaseOutOfDate').returns({migrate:false});
|
||||
sandbox.spy(migration.update, 'execute');
|
||||
|
||||
sandbox.stub(versioning, 'getDatabaseVersion', function () {
|
||||
return Promise.resolve('006');
|
||||
|
@ -83,8 +81,32 @@ describe('server bootstrap', function () {
|
|||
|
||||
bootstrap()
|
||||
.then(function () {
|
||||
migration.update.calledOnce.should.eql(true);
|
||||
migration.update.calledWith({
|
||||
migration.update.isDatabaseOutOfDate.calledOnce.should.eql(true);
|
||||
migration.update.execute.called.should.eql(false);
|
||||
models.Settings.populateDefaults.callCount.should.eql(1);
|
||||
migration.populate.calledOnce.should.eql(false);
|
||||
|
||||
done();
|
||||
})
|
||||
.catch(function (err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it('database does exist: expect update', function (done) {
|
||||
sandbox.stub(migration.update, 'isDatabaseOutOfDate').returns({migrate:true});
|
||||
sandbox.stub(migration.update, 'execute').returns(Promise.resolve());
|
||||
|
||||
sandbox.stub(versioning, 'getDatabaseVersion', function () {
|
||||
return Promise.resolve('006');
|
||||
});
|
||||
|
||||
bootstrap()
|
||||
.then(function () {
|
||||
migration.update.isDatabaseOutOfDate.calledOnce.should.eql(true);
|
||||
migration.update.execute.calledOnce.should.eql(true);
|
||||
|
||||
migration.update.execute.calledWith({
|
||||
fromVersion: '006',
|
||||
toVersion: '006',
|
||||
forceMigration: undefined
|
||||
|
|
Loading…
Add table
Reference in a new issue