Skip to content

Commit 144e4ad

Browse files
support backup/restore config (#129)
1 parent e262df8 commit 144e4ad

File tree

4 files changed

+305
-4
lines changed

4 files changed

+305
-4
lines changed

src/backup/backupCreator.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,12 @@ import {
77
import BackupCreateStatusGetter from './backupCreateStatusGetter';
88
import Connection from '../connection';
99
import { CommandBase } from '../validation/commandBase';
10-
import { BackupCreateRequest, BackupCreateResponse, BackupCreateStatusResponse } from '../openapi/types';
10+
import {
11+
BackupCreateRequest,
12+
BackupCreateResponse,
13+
BackupCreateStatusResponse,
14+
BackupConfig,
15+
} from '../openapi/types';
1116
import { Backend } from '.';
1217

1318
const WAIT_INTERVAL = 1000;
@@ -19,6 +24,7 @@ export default class BackupCreator extends CommandBase {
1924
private includeClassNames?: string[];
2025
private statusGetter: BackupCreateStatusGetter;
2126
private waitForCompletion!: boolean;
27+
private config?: BackupConfig;
2228

2329
constructor(client: Connection, statusGetter: BackupCreateStatusGetter) {
2430
super(client);
@@ -58,6 +64,11 @@ export default class BackupCreator extends CommandBase {
5864
return this;
5965
}
6066

67+
withConfig(cfg: BackupConfig) {
68+
this.config = cfg;
69+
return this;
70+
}
71+
6172
validate = (): void => {
6273
this.addErrors([
6374
...validateIncludeClassNames(this.includeClassNames),
@@ -75,7 +86,7 @@ export default class BackupCreator extends CommandBase {
7586

7687
const payload = {
7788
id: this.backupId,
78-
config: {},
89+
config: this.config,
7990
include: this.includeClassNames,
8091
exclude: this.excludeClassNames,
8192
} as BackupCreateRequest;

src/backup/backupRestorer.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,12 @@ import {
77
import Connection from '../connection';
88
import BackupRestoreStatusGetter from './backupRestoreStatusGetter';
99
import { CommandBase } from '../validation/commandBase';
10-
import { BackupRestoreRequest, BackupRestoreResponse, BackupRestoreStatusResponse } from '../openapi/types';
10+
import {
11+
BackupRestoreRequest,
12+
BackupRestoreResponse,
13+
BackupRestoreStatusResponse,
14+
RestoreConfig,
15+
} from '../openapi/types';
1116
import { Backend } from '.';
1217

1318
const WAIT_INTERVAL = 1000;
@@ -19,6 +24,7 @@ export default class BackupRestorer extends CommandBase {
1924
private includeClassNames?: string[];
2025
private statusGetter: BackupRestoreStatusGetter;
2126
private waitForCompletion?: boolean;
27+
private config?: RestoreConfig;
2228

2329
constructor(client: Connection, statusGetter: BackupRestoreStatusGetter) {
2430
super(client);
@@ -58,6 +64,11 @@ export default class BackupRestorer extends CommandBase {
5864
return this;
5965
}
6066

67+
withConfig(cfg: RestoreConfig) {
68+
this.config = cfg;
69+
return this;
70+
}
71+
6172
validate = (): void => {
6273
this.addErrors([
6374
...validateIncludeClassNames(this.includeClassNames || []),
@@ -74,7 +85,7 @@ export default class BackupRestorer extends CommandBase {
7485
}
7586

7687
const payload = {
77-
config: {},
88+
config: this.config,
7889
include: this.includeClassNames,
7990
exclude: this.excludeClassNames,
8091
} as BackupRestoreRequest;

src/backup/journey.test.ts

Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,283 @@ describe('fail restoring backup for both include and exclude classes', () => {
674674
it('cleans up', () => cleanupTestFood(client).catch(() => Promise.resolve('ignore not exising Pizza')));
675675
});
676676

677+
describe('creates backup with valid compression config values', () => {
678+
const BACKEND: Backend = 'filesystem';
679+
const BACKUP_ID = randomBackupId();
680+
681+
const client = weaviate.client({
682+
scheme: 'http',
683+
host: 'localhost:8080',
684+
});
685+
686+
it('sets up', () => createTestFoodSchemaAndData(client));
687+
688+
it('creates backup', () => {
689+
return client.backup
690+
.creator()
691+
.withIncludeClassNames(PIZZA_CLASS_NAME, SOUP_CLASS_NAME)
692+
.withBackend(BACKEND)
693+
.withBackupId(BACKUP_ID)
694+
.withWaitForCompletion(true)
695+
.withConfig({
696+
CPUPercentage: 80,
697+
ChunkSize: 512,
698+
CompressionLevel: 'BestSpeed',
699+
})
700+
.do()
701+
.catch((err: Error) => {
702+
throw new Error('should not fail on create backup: ' + err);
703+
});
704+
});
705+
706+
it('cleans up', () => cleanupTestFood(client));
707+
});
708+
709+
describe('fails creating backup with invalid compression config', () => {
710+
const BACKEND: Backend = 'filesystem';
711+
const BACKUP_ID = randomBackupId();
712+
713+
const client = weaviate.client({
714+
scheme: 'http',
715+
host: 'localhost:8080',
716+
});
717+
718+
it('sets up', () => createTestFoodSchemaAndData(client));
719+
720+
it('fails creating backup with CPUPercentage too high', () => {
721+
return client.backup
722+
.creator()
723+
.withIncludeClassNames(PIZZA_CLASS_NAME)
724+
.withBackend(BACKEND)
725+
.withBackupId(BACKUP_ID)
726+
.withConfig({
727+
CPUPercentage: 81, // Max is 80
728+
})
729+
.do()
730+
.then(() => {
731+
throw new Error('should fail on create backup');
732+
})
733+
.catch((err: Error) => {
734+
expect(err.message).toContain('422');
735+
expect(err.message).toContain('CPUPercentage');
736+
});
737+
});
738+
739+
it('fails creating backup with CPUPercentage too low', () => {
740+
return client.backup
741+
.creator()
742+
.withIncludeClassNames(PIZZA_CLASS_NAME)
743+
.withBackend(BACKEND)
744+
.withBackupId(BACKUP_ID)
745+
.withConfig({
746+
CPUPercentage: -1,
747+
})
748+
.do()
749+
.then(() => {
750+
throw new Error('should fail on create backup');
751+
})
752+
.catch((err: Error) => {
753+
expect(err.message).toContain('422');
754+
expect(err.message).toContain('CPUPercentage');
755+
});
756+
});
757+
758+
it('fails creating backup with ChunkSize too high', () => {
759+
return client.backup
760+
.creator()
761+
.withIncludeClassNames(PIZZA_CLASS_NAME)
762+
.withBackend(BACKEND)
763+
.withBackupId(BACKUP_ID)
764+
.withConfig({
765+
ChunkSize: 513, // Max is 512
766+
})
767+
.do()
768+
.then(() => {
769+
throw new Error('should fail on create backup');
770+
})
771+
.catch((err: Error) => {
772+
expect(err.message).toContain('422');
773+
expect(err.message).toContain('ChunkSize');
774+
});
775+
});
776+
777+
it('fails creating backup with ChunkSize too low', () => {
778+
return client.backup
779+
.creator()
780+
.withIncludeClassNames(PIZZA_CLASS_NAME)
781+
.withBackend(BACKEND)
782+
.withBackupId(BACKUP_ID)
783+
.withConfig({
784+
ChunkSize: 1, // Min is 2
785+
})
786+
.do()
787+
.then(() => {
788+
throw new Error('should fail on create backup');
789+
})
790+
.catch((err: Error) => {
791+
expect(err.message).toContain('422');
792+
expect(err.message).toContain('ChunkSize');
793+
});
794+
});
795+
796+
it('cleans up', () => cleanupTestFood(client));
797+
});
798+
799+
describe('restores backup with valid compression config values', () => {
800+
const BACKEND: Backend = 'filesystem';
801+
const BACKUP_ID = randomBackupId();
802+
803+
const client = weaviate.client({
804+
scheme: 'http',
805+
host: 'localhost:8080',
806+
});
807+
808+
it('sets up', () => createTestFoodSchemaAndData(client));
809+
810+
it('asserts data exist', () => assertThatAllPizzasExist(client));
811+
812+
it('creates backup', () => {
813+
return client.backup
814+
.creator()
815+
.withIncludeClassNames(PIZZA_CLASS_NAME)
816+
.withBackend(BACKEND)
817+
.withBackupId(BACKUP_ID)
818+
.withWaitForCompletion(true)
819+
.do()
820+
.catch((err: any) => {
821+
throw new Error('should not fail on create backup: ' + err);
822+
});
823+
});
824+
825+
it('removes existing class', () => {
826+
return client.schema
827+
.classDeleter()
828+
.withClassName(PIZZA_CLASS_NAME)
829+
.do()
830+
.catch((err: any) => {
831+
throw new Error('should not fail on class delete: ' + err);
832+
});
833+
});
834+
835+
it('restores backup', () => {
836+
return client.backup
837+
.restorer()
838+
.withIncludeClassNames(PIZZA_CLASS_NAME)
839+
.withBackend(BACKEND)
840+
.withBackupId(BACKUP_ID)
841+
.withWaitForCompletion(true)
842+
.withConfig({
843+
CPUPercentage: 80,
844+
})
845+
.do()
846+
.then((restoreResponse: BackupRestoreResponse) => {
847+
expect(restoreResponse.status).toBe('SUCCESS');
848+
expect(restoreResponse.error).toBeUndefined();
849+
})
850+
.catch((err: Error) => {
851+
throw new Error('should not fail on restore backup: ' + err);
852+
});
853+
});
854+
855+
it('asserts data again exist', () => assertThatAllPizzasExist(client));
856+
857+
it('checks restore status', () => {
858+
return client.backup
859+
.restoreStatusGetter()
860+
.withBackend(BACKEND)
861+
.withBackupId(BACKUP_ID)
862+
.do()
863+
.then((restoreStatusResponse: BackupRestoreStatusResponse) => {
864+
expect(restoreStatusResponse.status).toBe('SUCCESS');
865+
expect(restoreStatusResponse.error).toBeUndefined();
866+
})
867+
.catch((err: Error) => {
868+
throw new Error('should not fail on restore status: ' + err);
869+
});
870+
});
871+
872+
it('cleans up', () => cleanupTestFood(client));
873+
});
874+
875+
describe('fails restoring backup with invalid compression config', () => {
876+
const BACKEND: Backend = 'filesystem';
877+
const BACKUP_ID = randomBackupId();
878+
879+
const client = weaviate.client({
880+
scheme: 'http',
881+
host: 'localhost:8080',
882+
});
883+
884+
it('sets up', () => createTestFoodSchemaAndData(client));
885+
886+
it('asserts data exist', () => assertThatAllPizzasExist(client));
887+
888+
it('creates backup', () => {
889+
return client.backup
890+
.creator()
891+
.withIncludeClassNames(PIZZA_CLASS_NAME)
892+
.withBackend(BACKEND)
893+
.withBackupId(BACKUP_ID)
894+
.withWaitForCompletion(true)
895+
.do()
896+
.catch((err: any) => {
897+
throw new Error('should not fail on create backup: ' + err);
898+
});
899+
});
900+
901+
it('removes existing class', () => {
902+
return client.schema
903+
.classDeleter()
904+
.withClassName(PIZZA_CLASS_NAME)
905+
.do()
906+
.catch((err: any) => {
907+
throw new Error('should not fail on class delete: ' + err);
908+
});
909+
});
910+
911+
it('fails restoring backup with too high CPUPercentage', () => {
912+
return client.backup
913+
.restorer()
914+
.withIncludeClassNames(PIZZA_CLASS_NAME)
915+
.withExcludeClassNames(SOUP_CLASS_NAME)
916+
.withBackend(BACKEND)
917+
.withBackupId(BACKUP_ID)
918+
.withConfig({
919+
CPUPercentage: 81, // Max is 80
920+
})
921+
.do()
922+
.then(() => {
923+
throw new Error('should fail on restore');
924+
})
925+
.catch((err: Error) => {
926+
expect(err.message).toContain('422');
927+
expect(err.message).toContain('CPUPercentage');
928+
});
929+
});
930+
931+
it('fails restoring backup with too low CPUPercentage', () => {
932+
return client.backup
933+
.restorer()
934+
.withIncludeClassNames(PIZZA_CLASS_NAME)
935+
.withExcludeClassNames(SOUP_CLASS_NAME)
936+
.withBackend(BACKEND)
937+
.withBackupId(BACKUP_ID)
938+
.withConfig({
939+
CPUPercentage: -1,
940+
})
941+
.do()
942+
.then(() => {
943+
throw new Error('should fail on restore');
944+
})
945+
.catch((err: Error) => {
946+
expect(err.message).toContain('422');
947+
expect(err.message).toContain('CPUPercentage');
948+
});
949+
});
950+
951+
it('cleans up', () => cleanupTestFood(client));
952+
});
953+
677954
// describe("get all exising backups", () => {
678955
// const BACKEND: Backend = 'filesystem';
679956
// const BACKUP_ID = randomBackupId()

src/openapi/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ export type BackupCreateStatusResponse = definitions['BackupCreateStatusResponse
1515
export type BackupRestoreRequest = definitions['BackupRestoreRequest'];
1616
export type BackupRestoreResponse = definitions['BackupRestoreResponse'];
1717
export type BackupRestoreStatusResponse = definitions['BackupRestoreStatusResponse'];
18+
export type BackupConfig = definitions['BackupConfig'];
19+
export type RestoreConfig = definitions['RestoreConfig'];
1820
// Batch
1921
export type BatchDelete = definitions['BatchDelete'];
2022
export type BatchDeleteResponse = definitions['BatchDeleteResponse'];

0 commit comments

Comments
 (0)