Skip to content

Commit 32602c0

Browse files
authored
Add API to batch query service order results (#126)
1 parent 2b6511e commit 32602c0

File tree

6 files changed

+155
-27
lines changed

6 files changed

+155
-27
lines changed

src/main/java/org/eclipse/xpanse/tofu/maker/api/controllers/OpenTofuMakerTaskResultApi.java

+69-2
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,24 @@
99
import io.swagger.v3.oas.annotations.Parameter;
1010
import io.swagger.v3.oas.annotations.tags.Tag;
1111
import jakarta.annotation.Resource;
12+
import java.util.ArrayList;
13+
import java.util.List;
14+
import java.util.Objects;
15+
import java.util.UUID;
1216
import lombok.extern.slf4j.Slf4j;
1317
import org.eclipse.xpanse.tofu.maker.models.response.OpenTofuResult;
18+
import org.eclipse.xpanse.tofu.maker.models.response.ReFetchResult;
19+
import org.eclipse.xpanse.tofu.maker.models.response.ReFetchState;
1420
import org.eclipse.xpanse.tofu.maker.opentofu.service.OpenTofuResultPersistenceManage;
1521
import org.springframework.http.HttpStatus;
1622
import org.springframework.http.MediaType;
1723
import org.springframework.http.ResponseEntity;
24+
import org.springframework.util.CollectionUtils;
1825
import org.springframework.web.bind.annotation.CrossOrigin;
1926
import org.springframework.web.bind.annotation.GetMapping;
2027
import org.springframework.web.bind.annotation.PathVariable;
28+
import org.springframework.web.bind.annotation.PostMapping;
29+
import org.springframework.web.bind.annotation.RequestBody;
2130
import org.springframework.web.bind.annotation.RequestMapping;
2231
import org.springframework.web.bind.annotation.ResponseStatus;
2332
import org.springframework.web.bind.annotation.RestController;
@@ -31,7 +40,15 @@ public class OpenTofuMakerTaskResultApi {
3140

3241
@Resource private OpenTofuResultPersistenceManage openTofuResultPersistenceManage;
3342

34-
@Tag(name = "RetrieveOpenTofuResult", description = "APIs for manage the task form tofu-maker.")
43+
/**
44+
* Retrieve stored openTofu result.
45+
*
46+
* @param requestId id of the request
47+
* @return response entity of the openTofu result
48+
*/
49+
@Tag(
50+
name = "RetrieveOpenTofuResult",
51+
description = "APIs to manually fetching task results from tofu-maker.")
3552
@Operation(
3653
description =
3754
"Method to retrieve stored openTofu result in case tofu-maker "
@@ -41,7 +58,57 @@ public class OpenTofuMakerTaskResultApi {
4158
public ResponseEntity<OpenTofuResult> getStoredTaskResultByRequestId(
4259
@Parameter(name = "requestId", description = "id of the request")
4360
@PathVariable("requestId")
44-
String requestId) {
61+
UUID requestId) {
4562
return openTofuResultPersistenceManage.retrieveOpenTofuResultByRequestId(requestId);
4663
}
64+
65+
/**
66+
* Batch retrieve stored openTofu results.
67+
*
68+
* @param requestIds list of request ids
69+
* @return list of re-fetch results
70+
*/
71+
@Tag(
72+
name = "RetrieveOpenTofuResult",
73+
description = "APIs to manually fetching task results from tofu-maker.")
74+
@Operation(description = "Method to batch retrieve stored openTofu results from tofu-maker.")
75+
@PostMapping(value = "/results/batch", consumes = MediaType.APPLICATION_JSON_VALUE)
76+
public List<ReFetchResult> getBatchTaskResults(
77+
@Parameter(description = "List of request IDs") @RequestBody List<UUID> requestIds) {
78+
if (CollectionUtils.isEmpty(requestIds)) {
79+
throw new IllegalArgumentException("requestIds cannot be empty.");
80+
}
81+
List<ReFetchResult> reFetchResults = new ArrayList<>();
82+
requestIds.forEach(
83+
requestId -> {
84+
try {
85+
ResponseEntity<OpenTofuResult> result =
86+
openTofuResultPersistenceManage.retrieveOpenTofuResultByRequestId(
87+
requestId);
88+
if (result.getStatusCode() == HttpStatus.OK
89+
&& Objects.nonNull(result.getBody())) {
90+
reFetchResults.add(
91+
ReFetchResult.builder()
92+
.openTofuResult(result.getBody())
93+
.state(ReFetchState.OK)
94+
.build());
95+
} else {
96+
reFetchResults.add(
97+
ReFetchResult.builder()
98+
.state(
99+
ReFetchState
100+
.RESULT_ALREADY_RETURNED_OR_REQUEST_ID_INVALID)
101+
.build());
102+
}
103+
} catch (Exception e) {
104+
reFetchResults.add(
105+
ReFetchResult.builder()
106+
.state(
107+
ReFetchState
108+
.RESULT_ALREADY_RETURNED_OR_REQUEST_ID_INVALID)
109+
.build());
110+
}
111+
});
112+
return reFetchResults;
113+
}
47114
}

src/main/java/org/eclipse/xpanse/tofu/maker/models/exceptions/OpenTofuApiExceptionHandler.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,12 @@ public class OpenTofuApiExceptionHandler {
2929

3030
/** Exception handler for IllegalArgumentException. */
3131
@ExceptionHandler({IllegalArgumentException.class})
32-
@ResponseStatus(HttpStatus.BAD_REQUEST)
32+
@ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY)
3333
@ResponseBody
3434
public Response handleIllegalArgumentException(IllegalArgumentException ex) {
3535
log.error("handleIllegalArgumentException: ", ex);
3636
return Response.errorResponse(
37-
ResultType.OPENTOFU_EXECUTION_FAILED, Collections.singletonList(ex.getMessage()));
37+
ResultType.UNPROCESSABLE_ENTITY, Collections.singletonList(ex.getMessage()));
3838
}
3939

4040
/** Exception handler for OpenTofuExecutorException. */
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* SPDX-FileCopyrightText: Huawei Inc.
4+
*/
5+
6+
package org.eclipse.xpanse.tofu.maker.models.response;
7+
8+
import io.swagger.v3.oas.annotations.media.Schema;
9+
import jakarta.validation.constraints.NotNull;
10+
import lombok.Builder;
11+
import lombok.Data;
12+
13+
/** Data model for re-fetching order result. */
14+
@Data
15+
@Builder
16+
public class ReFetchResult {
17+
18+
@NotNull
19+
@Schema(description = "State of the re-fetching request")
20+
private ReFetchState state;
21+
22+
@Schema(description = "Result of the service order executed by open tofu.")
23+
private OpenTofuResult openTofuResult;
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* SPDX-FileCopyrightText: Huawei Inc.
4+
*/
5+
6+
package org.eclipse.xpanse.tofu.maker.models.response;
7+
8+
import com.fasterxml.jackson.annotation.JsonCreator;
9+
import com.fasterxml.jackson.annotation.JsonValue;
10+
import org.apache.commons.lang3.StringUtils;
11+
12+
/** ReFetch state for the REST API. */
13+
public enum ReFetchState {
14+
OK("OK"),
15+
RESULT_ALREADY_RETURNED_OR_REQUEST_ID_INVALID("ResultAlreadyReturnedOrRequestIdInvalid");
16+
17+
private final String state;
18+
19+
ReFetchState(String state) {
20+
this.state = state;
21+
}
22+
23+
/** For ReFetchState deserialize. */
24+
@JsonValue
25+
public String toValue() {
26+
return this.state;
27+
}
28+
29+
/** For ReFetchState serialize. */
30+
@JsonCreator
31+
public ReFetchState getByValue(String name) {
32+
for (ReFetchState state : values()) {
33+
if (StringUtils.equalsIgnoreCase(state.state, name)) {
34+
return state;
35+
}
36+
}
37+
return null;
38+
}
39+
}

src/main/java/org/eclipse/xpanse/tofu/maker/opentofu/service/OpenTofuResultPersistenceManage.java

+18-20
Original file line numberDiff line numberDiff line change
@@ -42,19 +42,14 @@ public class OpenTofuResultPersistenceManage {
4242
* @param result OpenTofuResult.
4343
*/
4444
public void persistOpenTofuResult(OpenTofuResult result) {
45-
String filePath = getFilePath(result.getRequestId());
46-
File file = new File(filePath);
47-
if (!file.exists() && !file.mkdirs()) {
45+
File filePath = getFilePath(result.getRequestId());
46+
if (!filePath.exists() && !filePath.mkdirs()) {
4847
log.error("Failed to create directory {}", filePath);
4948
return;
5049
}
50+
File file = new File(filePath, getFileName(result.getRequestId()));
5151
byte[] openTofuResultData = openTofuResultSerializer.serialize(result);
52-
try (FileOutputStream fos =
53-
new FileOutputStream(
54-
file.getPath()
55-
+ File.separator
56-
+ result.getRequestId()
57-
+ TF_RESULT_FILE_SUFFIX)) {
52+
try (FileOutputStream fos = new FileOutputStream(file)) {
5853
fos.write(openTofuResultData);
5954
log.info(
6055
"openTofu result successfully stored to directoryName: {}",
@@ -74,10 +69,10 @@ public void persistOpenTofuResult(OpenTofuResult result) {
7469
* @param requestId requestId.
7570
* @return OpenTofuResult.
7671
*/
77-
public ResponseEntity<OpenTofuResult> retrieveOpenTofuResultByRequestId(String requestId) {
78-
String filePath = getFilePath(UUID.fromString(requestId));
79-
File resultFile = new File(filePath + File.separator + requestId + TF_RESULT_FILE_SUFFIX);
72+
public ResponseEntity<OpenTofuResult> retrieveOpenTofuResultByRequestId(UUID requestId) {
73+
File resultFile = new File(getFilePath(requestId), getFileName(requestId));
8074
if (!resultFile.exists() && !resultFile.isFile()) {
75+
log.warn("Result file does not exist: {}", resultFile.getAbsolutePath());
8176
if (isDeployingInProgress(requestId)) {
8277
return ResponseEntity.noContent().build();
8378
}
@@ -89,7 +84,7 @@ public ResponseEntity<OpenTofuResult> retrieveOpenTofuResultByRequestId(String r
8984
OpenTofuResult openTofuResult =
9085
openTofuResultSerializer.deserialize(openTofuResultData);
9186
fis.close();
92-
deleteResultFileAndDirectory(new File(filePath));
87+
deleteResultFileAndDirectory(resultFile);
9388
return ResponseEntity.ok(openTofuResult);
9489
} catch (IOException e) {
9590
log.error("Failed to retrieve OpenTofuResult for requestId: {}", requestId, e);
@@ -98,8 +93,8 @@ public ResponseEntity<OpenTofuResult> retrieveOpenTofuResultByRequestId(String r
9893
}
9994
}
10095

101-
private boolean isDeployingInProgress(String requestId) {
102-
String workspace = scriptsHelper.buildTaskWorkspace(requestId);
96+
private boolean isDeployingInProgress(UUID requestId) {
97+
String workspace = scriptsHelper.buildTaskWorkspace(requestId.toString());
10398
File targetFile;
10499
if (cleanWorkspaceAfterDeployment) {
105100
targetFile = new File(workspace);
@@ -113,10 +108,9 @@ private boolean isDeployingInProgress(String requestId) {
113108
private void deleteResultFileAndDirectory(File resultFile) {
114109
try {
115110
deleteRecursively(resultFile);
116-
log.info("File folder deleted successfully: " + resultFile.getAbsolutePath());
111+
log.info("File folder deleted successfully: {}", resultFile.getAbsolutePath());
117112
} catch (Exception e) {
118-
log.error("An error occurred while deleting files: " + e.getMessage());
119-
e.printStackTrace();
113+
log.error("An error occurred while deleting files: {}", e.getMessage());
120114
}
121115
}
122116

@@ -132,7 +126,11 @@ private void deleteRecursively(File file) {
132126
file.delete();
133127
}
134128

135-
private String getFilePath(UUID requestId) {
136-
return failedCallbackStoreLocation + File.separator + requestId.toString();
129+
private File getFilePath(UUID requestId) {
130+
return new File(failedCallbackStoreLocation + File.separator + requestId);
131+
}
132+
133+
private String getFileName(UUID requestId) {
134+
return requestId + TF_RESULT_FILE_SUFFIX;
137135
}
138136
}

src/main/resources/application-dev.properties

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
tofu.maker.webhook.hmac.request.signing.key=1c30e4b1fad574f88572e25d0da03f34365f4ae92eda22bfd3a8c53cb5102f27
66
authorization.server.endpoint=http://localhost:8088
77
# set authorization client id for api
8-
authorization.api.client.id=302705713103306755
8+
authorization.api.client.id=306935357671276547
99
# set authorization client secret for api
10-
authorization.api.client.secret=8cCu3PTpLPz3kBfB5aFCX32IdhIlmPZCic5aFNHCR6na8TW1ZIhFOR3v1s3GVBYx
10+
authorization.api.client.secret=AhOc8tsQv8nzk5diQx4EscdoEUKkVfTLM8R06mw7xZ5HIWViiOkfBK6VEWaRCXPR
1111
# set authorization client id for swagger-ui
12-
authorization.swagger.ui.client.id=302705713271078915
12+
authorization.swagger.ui.client.id=306935358862458883

0 commit comments

Comments
 (0)