Skip to content

Commit

Permalink
Server: Fixed S3 storage connection and improved connectiob checks
Browse files Browse the repository at this point in the history
  • Loading branch information
laurent22 committed Nov 11, 2021
1 parent 01826d9 commit 4fc3bcb
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 31 deletions.
9 changes: 9 additions & 0 deletions packages/server/src/app.ts
Expand Up @@ -21,6 +21,7 @@ import newModelFactory from './models/factory';
import setupCommands from './utils/setupCommands';
import { RouteResponseFormat, routeResponseFormat } from './utils/routeUtils';
import { parseEnv } from './env';
import storageConnectionCheck from './utils/storageConnectionCheck';

interface Argv {
env?: Env;
Expand Down Expand Up @@ -282,6 +283,14 @@ async function main() {
appLogger().info('Starting services...');
await startServices(ctx.joplinBase.services);

appLogger().info('Performing main storage check...');
appLogger().info(await storageConnectionCheck(config().storageDriver, ctx.joplinBase.db, ctx.joplinBase.models));

if (config().storageDriverFallback) {
appLogger().info('Performing fallback storage check...');
appLogger().info(await storageConnectionCheck(config().storageDriverFallback, ctx.joplinBase.db, ctx.joplinBase.models));
}

appLogger().info(`Call this for testing: \`curl ${config().apiBaseUrl}/api/ping\``);

app.listen(config().port);
Expand Down
32 changes: 2 additions & 30 deletions packages/server/src/commands/StorageCommand.ts
Expand Up @@ -2,9 +2,7 @@ import { PositionalOptions, Options } from 'yargs';
import Logger from '@joplin/lib/Logger';
import BaseCommand, { RunContext } from './BaseCommand';
import parseStorageConnectionString from '../models/items/storage/parseStorageConnectionString';
import loadStorageDriver from '../models/items/storage/loadStorageDriver';
import uuidgen from '../utils/uuidgen';
import { Context } from '../models/items/storage/StorageDriverBase';
import storageConnectionCheck from '../utils/storageConnectionCheck';

const logger = Logger.create('ImportContentCommand');

Expand Down Expand Up @@ -72,33 +70,7 @@ export default class StorageCommand extends BaseCommand {
},

[ArgvCommand.CheckConnection]: async () => {
const storageConfig = parseStorageConnectionString(argv.connection);
const driver = await loadStorageDriver(storageConfig, runContext.db, { assignDriverId: false });
const itemId = `testingconnection${uuidgen(8)}`;
const itemContent = Buffer.from(uuidgen(8));
const context: Context = { models: runContext.models };

try {
await driver.write(itemId, itemContent, context);
} catch (error) {
error.message = `Could not write content to storage: ${error.message}`;
throw error;
}

if (!(await driver.exists(itemId, context))) {
throw new Error(`Written item does not exist: ${itemId}`);
}

const readContent = await driver.read(itemId, context);
if (readContent.toString() !== itemContent.toString()) throw new Error(`Could not read back written item. Expected: ${itemContent.toString()}. Got: ${readContent.toString()}`);

await driver.delete(itemId, context);

if (await driver.exists(itemId, context)) {
throw new Error(`Deleted item still exist: ${itemId}`);
}

logger.info('Item was written, read back and deleted without any error.');
logger.info(await storageConnectionCheck(argv.connection, runContext.db, runContext.models));
},
};

Expand Down
Expand Up @@ -8,6 +8,7 @@ import StorageDriverBase from './StorageDriverBase';
import StorageDriverDatabase from './StorageDriverDatabase';
import StorageDriverFs from './StorageDriverFs';
import StorageDriverMemory from './StorageDriverMemory';
import StorageDriverS3 from './StorageDriverS3';

export interface Options {
assignDriverId?: boolean;
Expand Down Expand Up @@ -62,7 +63,7 @@ export default async function(config: StorageDriverConfig | number, db: DbConnec
}

if (config.type === StorageDriverType.S3) {
return new StorageDriverMemory(storageId, config);
return new StorageDriverS3(storageId, config);
}

throw new Error(`Invalid config type: ${JSON.stringify(config)}`);
Expand Down
40 changes: 40 additions & 0 deletions packages/server/src/utils/storageConnectionCheck.ts
@@ -0,0 +1,40 @@
import { DbConnection } from '../db';
import { Models } from '../models/factory';
import loadStorageDriver from '../models/items/storage/loadStorageDriver';
import parseStorageConnectionString from '../models/items/storage/parseStorageConnectionString';
import { Context } from '../models/items/storage/StorageDriverBase';
import { StorageDriverConfig, StorageDriverType } from './types';
import uuidgen from './uuidgen';

export default async function(connection: string | StorageDriverConfig, db: DbConnection, models: Models): Promise<string> {
const storageConfig = typeof connection === 'string' ? parseStorageConnectionString(connection) : connection;

if (storageConfig.type === StorageDriverType.Database) return 'Database storage is special and cannot be checked this way. If the connection to the database was successful then the storage driver should work too.';

const driver = await loadStorageDriver(storageConfig, db, { assignDriverId: false });
const itemId = `testingconnection${uuidgen(8)}`;
const itemContent = Buffer.from(uuidgen(8));
const context: Context = { models };

try {
await driver.write(itemId, itemContent, context);
} catch (error) {
error.message = `Could not write content to storage: ${error.message}`;
throw error;
}

if (!(await driver.exists(itemId, context))) {
throw new Error(`Written item does not exist: ${itemId}`);
}

const readContent = await driver.read(itemId, context);
if (readContent.toString() !== itemContent.toString()) throw new Error(`Could not read back written item. Expected: ${itemContent.toString()}. Got: ${readContent.toString()}`);

await driver.delete(itemId, context);

if (await driver.exists(itemId, context)) {
throw new Error(`Deleted item still exist: ${itemId}`);
}

return 'Item was written, read back and deleted without any error.';
}

0 comments on commit 4fc3bcb

Please sign in to comment.