mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-30 10:36:35 +02:00
Server: Added command to test a storage connection
This commit is contained in:
parent
4879edc59a
commit
c6dec0a045
@ -1,54 +0,0 @@
|
||||
import { PositionalOptions, Options } from 'yargs';
|
||||
import Logger from '@joplin/lib/Logger';
|
||||
import BaseCommand, { RunContext } from './BaseCommand';
|
||||
import parseStorageConnectionString from '../models/items/storage/parseStorageConnectionString';
|
||||
|
||||
const logger = Logger.create('ImportContentCommand');
|
||||
|
||||
interface Argv {
|
||||
toStorage: string;
|
||||
batchSize?: number;
|
||||
}
|
||||
|
||||
export default class ImportContentCommand extends BaseCommand {
|
||||
|
||||
public command() {
|
||||
return 'import-content <to-storage>';
|
||||
}
|
||||
|
||||
public description() {
|
||||
return 'import content to storage';
|
||||
}
|
||||
|
||||
public positionals(): Record<string, PositionalOptions> {
|
||||
return {
|
||||
'to-storage': {
|
||||
description: 'storage connection string',
|
||||
type: 'string',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
public options(): Record<string, Options> {
|
||||
return {
|
||||
'batch-size': {
|
||||
type: 'number',
|
||||
description: 'Item batch size',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
public async run(argv: Argv, runContext: RunContext): Promise<void> {
|
||||
const toStorageConfig = parseStorageConnectionString(argv.toStorage);
|
||||
const batchSize = argv.batchSize || 1000;
|
||||
|
||||
logger.info('Importing to storage:', toStorageConfig);
|
||||
logger.info(`Batch size: ${batchSize}`);
|
||||
|
||||
await runContext.models.item().importContentToStorage(toStorageConfig, {
|
||||
batchSize: batchSize || 1000,
|
||||
logger: logger as Logger,
|
||||
});
|
||||
}
|
||||
|
||||
}
|
108
packages/server/src/commands/StorageCommand.ts
Normal file
108
packages/server/src/commands/StorageCommand.ts
Normal file
@ -0,0 +1,108 @@
|
||||
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';
|
||||
|
||||
const logger = Logger.create('ImportContentCommand');
|
||||
|
||||
enum ArgvCommand {
|
||||
Import = 'import',
|
||||
CheckConnection = 'check-connection',
|
||||
}
|
||||
|
||||
interface Argv {
|
||||
command: ArgvCommand;
|
||||
connection: string;
|
||||
batchSize?: number;
|
||||
}
|
||||
|
||||
export default class StorageCommand extends BaseCommand {
|
||||
|
||||
public command() {
|
||||
return 'storage <command>';
|
||||
}
|
||||
|
||||
public description() {
|
||||
return 'import content to storage';
|
||||
}
|
||||
|
||||
public positionals(): Record<string, PositionalOptions> {
|
||||
return {
|
||||
'command': {
|
||||
description: 'command to execute',
|
||||
choices: [
|
||||
ArgvCommand.Import,
|
||||
ArgvCommand.CheckConnection,
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
public options(): Record<string, Options> {
|
||||
return {
|
||||
'batch-size': {
|
||||
type: 'number',
|
||||
description: 'Item batch size',
|
||||
},
|
||||
'connection': {
|
||||
description: 'storage connection string',
|
||||
type: 'string',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
public async run(argv: Argv, runContext: RunContext): Promise<void> {
|
||||
const commands: Record<ArgvCommand, Function> = {
|
||||
[ArgvCommand.Import]: async () => {
|
||||
if (!argv.connection) throw new Error('--connection option is required');
|
||||
|
||||
const toStorageConfig = parseStorageConnectionString(argv.connection);
|
||||
const batchSize = argv.batchSize || 1000;
|
||||
|
||||
logger.info('Importing to storage:', toStorageConfig);
|
||||
logger.info(`Batch size: ${batchSize}`);
|
||||
|
||||
await runContext.models.item().importContentToStorage(toStorageConfig, {
|
||||
batchSize: batchSize || 1000,
|
||||
logger: logger as Logger,
|
||||
});
|
||||
},
|
||||
|
||||
[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.');
|
||||
},
|
||||
};
|
||||
|
||||
await commands[argv.command]();
|
||||
}
|
||||
|
||||
}
|
@ -2,7 +2,7 @@ import yargs = require('yargs');
|
||||
import BaseCommand from '../commands/BaseCommand';
|
||||
import DbCommand from '../commands/DbCommand';
|
||||
import DeleteOldChangesCommand from '../commands/DeleteOldChangesCommand';
|
||||
import ImportContentCommand from '../commands/ImportContentCommand';
|
||||
import StorageCommand from '../commands/StorageCommand';
|
||||
import MigrateCommand from '../commands/MigrateCommand';
|
||||
|
||||
export interface Commands {
|
||||
@ -17,7 +17,7 @@ export default async function setupCommands(): Promise<Commands> {
|
||||
new MigrateCommand(),
|
||||
new DbCommand(),
|
||||
new DeleteOldChangesCommand(),
|
||||
new ImportContentCommand(),
|
||||
new StorageCommand(),
|
||||
];
|
||||
|
||||
for (const cmd of commands) {
|
||||
|
Loading…
Reference in New Issue
Block a user