Abort when MinIO bucket does not have versioning enabled #545 (#546)

Co-authored-by: Florent FAYOLLE <florent.fayolle@beta.gouv.fr>
pull/563/head
Florent 11 months ago committed by GitHub
parent a56b0448ff
commit b6b2d05be0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1124,7 +1124,6 @@ export class FlexServer implements GristServer {
await this.loadConfig(); await this.loadConfig();
this.addComm(); this.addComm();
await this.create.configure?.();
if (!isSingleUserMode()) { if (!isSingleUserMode()) {
const externalStorage = appSettings.section('externalStorage'); const externalStorage = appSettings.section('externalStorage');
const haveExternalStorage = Object.values(externalStorage.nested) const haveExternalStorage = Object.values(externalStorage.nested)
@ -1135,6 +1134,7 @@ export class FlexServer implements GristServer {
this._disableExternalStorage = true; this._disableExternalStorage = true;
externalStorage.flag('active').set(false); externalStorage.flag('active').set(false);
} }
await this.create.configure?.();
const workers = this._docWorkerMap; const workers = this._docWorkerMap;
const docWorkerId = await this._addSelfAsWorker(workers); const docWorkerId = await this._addSelfAsWorker(workers);

@ -50,6 +50,7 @@ export interface ICreateActiveDocOptions {
export interface ICreateStorageOptions { export interface ICreateStorageOptions {
name: string; name: string;
check(): boolean; check(): boolean;
checkBackend?(): Promise<void>;
create(purpose: 'doc'|'meta', extraPrefix: string): ExternalStorage|undefined; create(purpose: 'doc'|'meta', extraPrefix: string): ExternalStorage|undefined;
} }
@ -119,7 +120,10 @@ export function makeSimpleCreator(opts: {
}, },
async configure() { async configure() {
for (const s of storage || []) { for (const s of storage || []) {
if (s.check()) { break; } if (s.check()) {
await s.checkBackend?.();
break;
}
} }
}, },
...(opts.shell && { ...(opts.shell && {

@ -107,6 +107,11 @@ export class MinIOExternalStorage implements ExternalStorage {
} }
} }
public async hasVersioning(): Promise<Boolean> {
const versioning = await this._s3.getBucketVersioning(this.bucket);
return versioning && versioning.Status === 'Enabled';
}
public async versions(key: string, options?: { includeDeleteMarkers?: boolean }) { public async versions(key: string, options?: { includeDeleteMarkers?: boolean }) {
const results: minio.BucketItem[] = []; const results: minio.BucketItem[] = [];
await new Promise((resolve, reject) => { await new Promise((resolve, reject) => {

@ -60,3 +60,16 @@ export function checkMinIOExternalStorage() {
region region
}; };
} }
export async function checkMinIOBucket() {
const options = checkMinIOExternalStorage();
if (!options) {
throw new Error('Configuration check failed for MinIO backend storage.');
}
const externalStorage = new MinIOExternalStorage(options.bucket, options);
if (!await externalStorage.hasVersioning()) {
await externalStorage.close();
throw new Error(`FATAL: the MinIO bucket "${options.bucket}" does not have versioning enabled`);
}
}

@ -106,6 +106,7 @@ export async function main(port: number, serverTypes: ServerType[],
server.addApiMiddleware(); server.addApiMiddleware();
await server.addBillingMiddleware(); await server.addBillingMiddleware();
try {
await server.start(); await server.start();
if (includeHome) { if (includeHome) {
@ -144,6 +145,10 @@ export async function main(port: number, serverTypes: ServerType[],
server.checkOptionCombinations(); server.checkOptionCombinations();
server.summary(); server.summary();
return server; return server;
} catch(e) {
await server.close();
throw e;
}
} }

@ -1,4 +1,4 @@
import { checkMinIOExternalStorage, import { checkMinIOBucket, checkMinIOExternalStorage,
configureMinIOExternalStorage } from 'app/server/lib/configureMinIOExternalStorage'; configureMinIOExternalStorage } from 'app/server/lib/configureMinIOExternalStorage';
import { makeSimpleCreator } from 'app/server/lib/ICreate'; import { makeSimpleCreator } from 'app/server/lib/ICreate';
import { Telemetry } from 'app/server/lib/Telemetry'; import { Telemetry } from 'app/server/lib/Telemetry';
@ -12,6 +12,7 @@ export const create = makeSimpleCreator({
{ {
name: 'minio', name: 'minio',
check: () => checkMinIOExternalStorage() !== undefined, check: () => checkMinIOExternalStorage() !== undefined,
checkBackend: () => checkMinIOBucket(),
create: configureMinIOExternalStorage, create: configureMinIOExternalStorage,
}, },
], ],

@ -117,5 +117,7 @@ export async function main() {
} }
if (require.main === module) { if (require.main === module) {
main().catch((err) => console.error(err)); main().catch((err) => {
console.error(err);
});
} }

Loading…
Cancel
Save