Skip to content

Commit ce9b4fa

Browse files
authored
Merge pull request #415 from weaviate/feat/users-restore
Add backup restore options for users and roles
2 parents 3615cfc + 8b792de commit ce9b4fa

9 files changed

Lines changed: 1197 additions & 846 deletions

File tree

src/main/java/io/weaviate/client/v1/async/backup/api/BackupRestorer.java

Lines changed: 78 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,18 @@
11
package io.weaviate.client.v1.async.backup.api;
22

3+
import java.util.List;
4+
import java.util.Optional;
5+
import java.util.concurrent.CompletableFuture;
6+
import java.util.concurrent.CompletionException;
7+
import java.util.concurrent.Executor;
8+
import java.util.concurrent.Future;
9+
10+
import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
11+
import org.apache.hc.core5.concurrent.FutureCallback;
12+
import org.apache.hc.core5.http.HttpStatus;
13+
314
import com.google.gson.annotations.SerializedName;
15+
416
import io.weaviate.client.Config;
517
import io.weaviate.client.base.AsyncBaseClient;
618
import io.weaviate.client.base.AsyncClientResult;
@@ -13,22 +25,13 @@
1325
import io.weaviate.client.v1.auth.provider.AccessTokenProvider;
1426
import io.weaviate.client.v1.backup.model.BackupRestoreResponse;
1527
import io.weaviate.client.v1.backup.model.BackupRestoreStatusResponse;
28+
import io.weaviate.client.v1.backup.model.RbacRestoreOption;
1629
import io.weaviate.client.v1.backup.model.RestoreStatus;
1730
import lombok.Builder;
1831
import lombok.Getter;
19-
import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
20-
import org.apache.hc.core5.concurrent.FutureCallback;
21-
import org.apache.hc.core5.http.HttpStatus;
22-
23-
import java.util.List;
24-
import java.util.Optional;
25-
import java.util.concurrent.CompletableFuture;
26-
import java.util.concurrent.CompletionException;
27-
import java.util.concurrent.Executor;
28-
import java.util.concurrent.Future;
2932

3033
public class BackupRestorer extends AsyncBaseClient<BackupRestoreResponse>
31-
implements AsyncClientResult<BackupRestoreResponse> {
34+
implements AsyncClientResult<BackupRestoreResponse> {
3235

3336
private static final long WAIT_INTERVAL = 1000;
3437

@@ -41,14 +44,13 @@ public class BackupRestorer extends AsyncBaseClient<BackupRestoreResponse>
4144
private boolean waitForCompletion;
4245
private final Executor executor;
4346

44-
45-
public BackupRestorer(CloseableHttpAsyncClient client, Config config, AccessTokenProvider tokenProvider, BackupRestoreStatusGetter statusGetter, Executor executor) {
47+
public BackupRestorer(CloseableHttpAsyncClient client, Config config, AccessTokenProvider tokenProvider,
48+
BackupRestoreStatusGetter statusGetter, Executor executor) {
4649
super(client, config, tokenProvider);
4750
this.statusGetter = statusGetter;
4851
this.executor = executor;
4952
}
5053

51-
5254
public BackupRestorer withIncludeClassNames(String... classNames) {
5355
this.includeClassNames = classNames;
5456
return this;
@@ -87,19 +89,20 @@ public Future<Result<BackupRestoreResponse>> run(FutureCallback<Result<BackupRes
8789
return restore(callback);
8890
}
8991

90-
9192
private Future<Result<BackupRestoreResponse>> restore(FutureCallback<Result<BackupRestoreResponse>> callback) {
9293
BackupRestore payload = BackupRestore.builder()
93-
.config(BackupRestoreConfig.builder().build())
94-
.include(includeClassNames)
95-
.exclude(excludeClassNames)
96-
.config(config)
97-
.build();
98-
String path = String.format("/backups/%s/%s/restore", UrlEncoder.encodePathParam(backend), UrlEncoder.encodePathParam(backupId));
94+
.config(BackupRestoreConfig.builder().build())
95+
.include(includeClassNames)
96+
.exclude(excludeClassNames)
97+
.config(config)
98+
.build();
99+
String path = String.format("/backups/%s/%s/restore", UrlEncoder.encodePathParam(backend),
100+
UrlEncoder.encodePathParam(backupId));
99101
return sendPostRequest(path, payload, BackupRestoreResponse.class, callback);
100102
}
101103

102-
private Future<Result<BackupRestoreResponse>> restoreAndWaitForCompletion(FutureCallback<Result<BackupRestoreResponse>> callback) {
104+
private Future<Result<BackupRestoreResponse>> restoreAndWaitForCompletion(
105+
FutureCallback<Result<BackupRestoreResponse>> callback) {
103106
CompletableFuture<Result<BackupRestoreResponse>> future = new CompletableFuture<>();
104107
FutureCallback<Result<BackupRestoreResponse>> internalCallback = new FutureCallback<Result<BackupRestoreResponse>>() {
105108
@Override
@@ -124,64 +127,65 @@ public void cancelled() {
124127
restore(internalCallback);
125128

126129
return future.thenCompose(restoreResult -> {
127-
if (restoreResult.hasErrors()) {
128-
return CompletableFuture.completedFuture(restoreResult);
129-
}
130-
return getStatusRecursively(backend, backupId, restoreResult);
131-
})
132-
.whenComplete((restoreResult, throwable) -> {
133-
if (callback != null) {
134-
if (throwable != null) {
135-
callback.failed((Exception) throwable);
136-
} else {
137-
callback.completed(restoreResult);
130+
if (restoreResult.hasErrors()) {
131+
return CompletableFuture.completedFuture(restoreResult);
132+
}
133+
return getStatusRecursively(backend, backupId, restoreResult);
134+
})
135+
.whenComplete((restoreResult, throwable) -> {
136+
if (callback != null) {
137+
if (throwable != null) {
138+
callback.failed((Exception) throwable);
139+
} else {
140+
callback.completed(restoreResult);
141+
}
138142
}
139-
}
140-
});
143+
});
141144
}
142145

143146
private CompletableFuture<Result<BackupRestoreStatusResponse>> getStatus(String backend, String backupId) {
144147
CompletableFuture<Result<BackupRestoreStatusResponse>> future = new CompletableFuture<>();
145148
statusGetter.withBackend(backend).withBackupId(backupId)
146-
.run(new FutureCallback<Result<BackupRestoreStatusResponse>>() {
147-
@Override
148-
public void completed(Result<BackupRestoreStatusResponse> createStatusResult) {
149-
future.complete(createStatusResult);
150-
}
149+
.run(new FutureCallback<Result<BackupRestoreStatusResponse>>() {
150+
@Override
151+
public void completed(Result<BackupRestoreStatusResponse> createStatusResult) {
152+
future.complete(createStatusResult);
153+
}
151154

152-
@Override
153-
public void failed(Exception e) {
154-
future.completeExceptionally(e);
155-
}
155+
@Override
156+
public void failed(Exception e) {
157+
future.completeExceptionally(e);
158+
}
156159

157-
@Override
158-
public void cancelled() {
159-
}
160-
});
160+
@Override
161+
public void cancelled() {
162+
}
163+
});
161164
return future;
162165
}
163166

164167
private CompletableFuture<Result<BackupRestoreResponse>> getStatusRecursively(String backend, String backupId,
165-
Result<BackupRestoreResponse> restoreResult) {
168+
Result<BackupRestoreResponse> restoreResult) {
166169
return Futures.thenComposeAsync(getStatus(backend, backupId), restoreStatusResult -> {
167170
boolean isRunning = Optional.of(restoreStatusResult)
168-
.filter(r -> !r.hasErrors())
169-
.map(Result::getResult)
170-
.map(BackupRestoreStatusResponse::getStatus)
171-
.filter(status -> {
172-
switch (status) {
173-
case RestoreStatus.SUCCESS:
174-
case RestoreStatus.FAILED:
175-
return false;
176-
default:
177-
return true;
178-
}
179-
})
180-
.isPresent();
171+
.filter(r -> !r.hasErrors())
172+
.map(Result::getResult)
173+
.map(BackupRestoreStatusResponse::getStatus)
174+
.filter(status -> {
175+
switch (status) {
176+
case RestoreStatus.SUCCESS:
177+
case RestoreStatus.FAILED:
178+
return false;
179+
default:
180+
return true;
181+
}
182+
})
183+
.isPresent();
181184

182185
if (isRunning) {
183186
try {
184-
return Futures.supplyDelayed(() -> getStatusRecursively(backend, backupId, restoreResult), WAIT_INTERVAL, executor);
187+
return Futures.supplyDelayed(() -> getStatusRecursively(backend, backupId, restoreResult), WAIT_INTERVAL,
188+
executor);
185189
} catch (InterruptedException e) {
186190
throw new CompletionException(e);
187191
}
@@ -191,7 +195,7 @@ private CompletableFuture<Result<BackupRestoreResponse>> getStatusRecursively(St
191195
}
192196

193197
private Result<BackupRestoreResponse> merge(Result<BackupRestoreStatusResponse> restoreStatusResult,
194-
Result<BackupRestoreResponse> restoreResult) {
198+
Result<BackupRestoreResponse> restoreResult) {
195199
BackupRestoreStatusResponse restoreStatusResponse = restoreStatusResult.getResult();
196200
BackupRestoreResponse restoreResponse = restoreResult.getResult();
197201

@@ -215,20 +219,22 @@ private Result<BackupRestoreResponse> merge(Result<BackupRestoreStatusResponse>
215219
List<WeaviateErrorMessage> messages = error.getMessages();
216220

217221
errorResponse = WeaviateErrorResponse.builder()
218-
.code(statusCode)
219-
.error(messages)
220-
.build();
222+
.code(statusCode)
223+
.error(messages)
224+
.build();
221225
}
222226

223227
return new Result<>(statusCode, merged, errorResponse);
224228
}
225229

226-
227230
@Getter
228231
@Builder
229232
private static class BackupRestore {
233+
@SerializedName("config")
230234
BackupRestoreConfig config;
235+
@SerializedName("include")
231236
String[] include;
237+
@SerializedName("exclude")
232238
String[] exclude;
233239
}
234240

@@ -241,5 +247,9 @@ public static class BackupRestoreConfig {
241247
String bucket;
242248
@SerializedName("Path")
243249
String path;
250+
@SerializedName("usersOptions")
251+
RbacRestoreOption usersRestore;
252+
@SerializedName("rolesOptions")
253+
RbacRestoreOption rolesRestore;
244254
}
245255
}

src/main/java/io/weaviate/client/v1/backup/api/BackupRestorer.java

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
package io.weaviate.client.v1.backup.api;
22

33
import com.google.gson.annotations.SerializedName;
4-
import io.weaviate.client.v1.backup.model.BackupRestoreResponse;
5-
import io.weaviate.client.v1.backup.model.BackupRestoreStatusResponse;
6-
import io.weaviate.client.v1.backup.model.RestoreStatus;
7-
import lombok.Builder;
8-
import lombok.Getter;
4+
95
import io.weaviate.client.Config;
106
import io.weaviate.client.base.BaseClient;
117
import io.weaviate.client.base.ClientResult;
128
import io.weaviate.client.base.Response;
139
import io.weaviate.client.base.Result;
1410
import io.weaviate.client.base.http.HttpClient;
11+
import io.weaviate.client.v1.backup.model.BackupRestoreResponse;
12+
import io.weaviate.client.v1.backup.model.BackupRestoreStatusResponse;
13+
import io.weaviate.client.v1.backup.model.RbacRestoreOption;
14+
import io.weaviate.client.v1.backup.model.RestoreStatus;
15+
import lombok.Builder;
16+
import lombok.Getter;
1517

1618
public class BackupRestorer extends BaseClient<BackupRestoreResponse> implements ClientResult<BackupRestoreResponse> {
1719

@@ -68,19 +70,17 @@ public BackupRestorer withWaitForCompletion(boolean waitForCompletion) {
6870
@Override
6971
public Result<BackupRestoreResponse> run() {
7072
BackupRestore payload = BackupRestore.builder()
71-
.config(BackupRestoreConfig.builder().build())
72-
.include(includeClassNames)
73-
.exclude(excludeClassNames)
74-
.config(config)
75-
.build();
73+
.include(includeClassNames)
74+
.exclude(excludeClassNames)
75+
.config(config)
76+
.build();
7677

7778
if (waitForCompletion) {
7879
return restoreAndWaitForCompletion(payload);
7980
}
8081
return restore(payload);
8182
}
8283

83-
8484
private Result<BackupRestoreResponse> restore(BackupRestore payload) {
8585
Response<BackupRestoreResponse> response = sendPostRequest(path(), payload, BackupRestoreResponse.class);
8686
return new Result<>(response);
@@ -93,7 +93,7 @@ private Result<BackupRestoreResponse> restoreAndWaitForCompletion(BackupRestore
9393
}
9494

9595
statusGetter.withBackend(backend).withBackupId(backupId);
96-
while(true) {
96+
while (true) {
9797
Response<BackupRestoreStatusResponse> statusResponse = statusGetter.statusRestore();
9898
if (new Result<>(statusResponse).hasErrors()) {
9999
return merge(statusResponse, result);
@@ -117,7 +117,8 @@ private String path() {
117117
return String.format("/backups/%s/%s/restore", backend, backupId);
118118
}
119119

120-
private Result<BackupRestoreResponse> merge(Response<BackupRestoreStatusResponse> response, Result<BackupRestoreResponse> result) {
120+
private Result<BackupRestoreResponse> merge(Response<BackupRestoreStatusResponse> response,
121+
Result<BackupRestoreResponse> result) {
121122
BackupRestoreStatusResponse statusRestoreResponse = response.getBody();
122123
BackupRestoreResponse restoreResponse = result.getResult();
123124

@@ -136,12 +137,14 @@ private Result<BackupRestoreResponse> merge(Response<BackupRestoreStatusResponse
136137
return new Result<>(response.getStatusCode(), merged, response.getErrors());
137138
}
138139

139-
140140
@Getter
141141
@Builder
142142
private static class BackupRestore {
143+
@SerializedName("config")
143144
BackupRestoreConfig config;
145+
@SerializedName("include")
144146
String[] include;
147+
@SerializedName("exclude")
145148
String[] exclude;
146149
}
147150

@@ -154,5 +157,9 @@ public static class BackupRestoreConfig {
154157
String bucket;
155158
@SerializedName("Path")
156159
String path;
160+
@SerializedName("usersOptions")
161+
RbacRestoreOption usersRestore;
162+
@SerializedName("rolesOptions")
163+
RbacRestoreOption rolesRestore;
157164
}
158165
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package io.weaviate.client.v1.backup.model;
2+
3+
import com.google.gson.annotations.SerializedName;
4+
5+
public enum RbacRestoreOption {
6+
@SerializedName("noRestore")
7+
NO_RESTORE,
8+
@SerializedName("all")
9+
ALL;
10+
}

src/test/java/io/weaviate/integration/client/WeaviateDockerCompose.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ public Weaviate(String dockerImageName, boolean withOffloadS3) {
5757
withEnv("DISABLE_TELEMETRY", "true");
5858
withEnv("PERSISTENCE_FLUSH_IDLE_MEMTABLES_AFTER", "1");
5959
withEnv("ENABLE_MODULES", String.join(",", enableModules));
60+
withEnv("AUTHENTICATION_DB_USERS_ENABLED", "true");
6061
withCreateContainerCmdModifier(cmd -> cmd.withHostName("weaviate"));
6162
}
6263
}

0 commit comments

Comments
 (0)