Skip to content

Commit 26efa6b

Browse files
committed
Update reFetch result of order
1 parent 2b6511e commit 26efa6b

File tree

8 files changed

+186
-86
lines changed

8 files changed

+186
-86
lines changed

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

+44-5
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,20 @@
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.UUID;
1215
import lombok.extern.slf4j.Slf4j;
13-
import org.eclipse.xpanse.tofu.maker.models.response.OpenTofuResult;
16+
import org.eclipse.xpanse.tofu.maker.models.response.ReFetchResult;
1417
import org.eclipse.xpanse.tofu.maker.opentofu.service.OpenTofuResultPersistenceManage;
1518
import org.springframework.http.HttpStatus;
1619
import org.springframework.http.MediaType;
17-
import org.springframework.http.ResponseEntity;
20+
import org.springframework.util.CollectionUtils;
1821
import org.springframework.web.bind.annotation.CrossOrigin;
1922
import org.springframework.web.bind.annotation.GetMapping;
2023
import org.springframework.web.bind.annotation.PathVariable;
24+
import org.springframework.web.bind.annotation.PostMapping;
25+
import org.springframework.web.bind.annotation.RequestBody;
2126
import org.springframework.web.bind.annotation.RequestMapping;
2227
import org.springframework.web.bind.annotation.ResponseStatus;
2328
import org.springframework.web.bind.annotation.RestController;
@@ -31,17 +36,51 @@ public class OpenTofuMakerTaskResultApi {
3136

3237
@Resource private OpenTofuResultPersistenceManage openTofuResultPersistenceManage;
3338

34-
@Tag(name = "RetrieveOpenTofuResult", description = "APIs for manage the task form tofu-maker.")
39+
/**
40+
* Retrieve stored openTofu result.
41+
*
42+
* @param requestId id of the request
43+
* @return response entity of the openTofu result
44+
*/
45+
@Tag(
46+
name = "RetrieveOpenTofuResult",
47+
description = "APIs to manually fetching task results from tofu-maker.")
3548
@Operation(
3649
description =
3750
"Method to retrieve stored openTofu result in case tofu-maker "
3851
+ "receives a failure while sending the openTofu result via callback.")
3952
@GetMapping(value = "/result/{requestId}", produces = MediaType.APPLICATION_JSON_VALUE)
4053
@ResponseStatus(HttpStatus.OK)
41-
public ResponseEntity<OpenTofuResult> getStoredTaskResultByRequestId(
54+
public ReFetchResult getStoredTaskResultByRequestId(
4255
@Parameter(name = "requestId", description = "id of the request")
4356
@PathVariable("requestId")
44-
String requestId) {
57+
UUID requestId) {
4558
return openTofuResultPersistenceManage.retrieveOpenTofuResultByRequestId(requestId);
4659
}
60+
61+
/**
62+
* Batch retrieve stored openTofu results.
63+
*
64+
* @param requestIds list of request ids
65+
* @return list of re-fetch results
66+
*/
67+
@Tag(
68+
name = "RetrieveOpenTofuResult",
69+
description = "APIs to manually fetching task results from tofu-maker.")
70+
@Operation(description = "Method to batch retrieve stored openTofu results from tofu-maker.")
71+
@PostMapping(value = "/results/batch", consumes = MediaType.APPLICATION_JSON_VALUE)
72+
public List<ReFetchResult> getBatchTaskResults(
73+
@Parameter(description = "List of request IDs") @RequestBody List<UUID> requestIds) {
74+
if (CollectionUtils.isEmpty(requestIds)) {
75+
throw new IllegalArgumentException("requestIds cannot be empty.");
76+
}
77+
List<ReFetchResult> reFetchResults = new ArrayList<>();
78+
requestIds.forEach(
79+
requestId -> {
80+
reFetchResults.add(
81+
openTofuResultPersistenceManage.retrieveOpenTofuResultByRequestId(
82+
requestId));
83+
});
84+
return reFetchResults;
85+
}
4786
}

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

+2-13
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. */
@@ -127,15 +127,4 @@ public Response handleInvalidOpenTofuScriptsException(InvalidOpenTofuScriptsExce
127127
return Response.errorResponse(
128128
ResultType.INVALID_OPENTOFU_SCRIPTS, Collections.singletonList(ex.getMessage()));
129129
}
130-
131-
/** Exception handler for ResultAlreadyReturnedOrRequestIdInvalidException. */
132-
@ExceptionHandler({ResultAlreadyReturnedOrRequestIdInvalidException.class})
133-
@ResponseStatus(HttpStatus.BAD_REQUEST)
134-
@ResponseBody
135-
public Response handleResultAlreadyReturnedOrRequestIdInvalidException(
136-
ResultAlreadyReturnedOrRequestIdInvalidException ex) {
137-
return Response.errorResponse(
138-
ResultType.RESULT_ALREADY_RETURNED_OR_REQUEST_ID_INVALID,
139-
Collections.singletonList(ex.getMessage()));
140-
}
141130
}

Diff for: src/main/java/org/eclipse/xpanse/tofu/maker/models/exceptions/ResultAlreadyReturnedOrRequestIdInvalidException.java

-13
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
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 java.util.UUID;
11+
import lombok.Builder;
12+
import lombok.Data;
13+
14+
/** Data model for re-fetching order result. */
15+
@Data
16+
@Builder
17+
public class ReFetchResult {
18+
19+
@NotNull
20+
@Schema(description = "Id of the request order.")
21+
private UUID requestId;
22+
23+
@NotNull
24+
@Schema(description = "State of the re-fetching result of order.")
25+
private ReFetchState state;
26+
27+
@Schema(description = "Result of the service order executed by open tofu.")
28+
private OpenTofuResult openTofuResult;
29+
30+
@Schema(description = "Error message of the re-fetching result of order.")
31+
private String errorMessage;
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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+
ORDER_IN_PROGRESS("OrderInProgress"),
16+
RESULT_NOT_FOUND("ResultNotFound"),
17+
RESULT_PARSE_FAILED("ResultInvalid");
18+
private final String state;
19+
20+
ReFetchState(String state) {
21+
this.state = state;
22+
}
23+
24+
/** For ReFetchState deserialize. */
25+
@JsonValue
26+
public String toValue() {
27+
return this.state;
28+
}
29+
30+
/** For ReFetchState serialize. */
31+
@JsonCreator
32+
public ReFetchState getByValue(String name) {
33+
for (ReFetchState state : values()) {
34+
if (StringUtils.equalsIgnoreCase(state.state, name)) {
35+
return state;
36+
}
37+
}
38+
return null;
39+
}
40+
}

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

+54-44
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@
1212
import java.io.IOException;
1313
import java.util.UUID;
1414
import lombok.extern.slf4j.Slf4j;
15-
import org.eclipse.xpanse.tofu.maker.models.exceptions.ResultAlreadyReturnedOrRequestIdInvalidException;
1615
import org.eclipse.xpanse.tofu.maker.models.response.OpenTofuResult;
16+
import org.eclipse.xpanse.tofu.maker.models.response.ReFetchResult;
17+
import org.eclipse.xpanse.tofu.maker.models.response.ReFetchState;
1718
import org.eclipse.xpanse.tofu.maker.utils.OpenTofuResultSerializer;
1819
import org.springframework.beans.factory.annotation.Value;
19-
import org.springframework.http.ResponseEntity;
2020
import org.springframework.stereotype.Component;
2121

2222
/** OpenTofu service classes are manage task result. */
@@ -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,49 +69,58 @@ 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);
80-
if (!resultFile.exists() && !resultFile.isFile()) {
72+
public ReFetchResult retrieveOpenTofuResultByRequestId(UUID requestId) {
73+
File resultFile = new File(getFilePath(requestId), getFileName(requestId));
74+
if (!isValidResultFile(resultFile)) {
75+
String errorMsg = String.format("Not found result file for requestId %s.", requestId);
8176
if (isDeployingInProgress(requestId)) {
82-
return ResponseEntity.noContent().build();
77+
errorMsg = errorMsg + " The order is still in progress.";
78+
return buildErrorResponse(requestId, errorMsg, ReFetchState.ORDER_IN_PROGRESS);
8379
}
84-
throw new ResultAlreadyReturnedOrRequestIdInvalidException(
85-
"Result file does not exist: " + resultFile.getAbsolutePath());
80+
return buildErrorResponse(requestId, errorMsg, ReFetchState.RESULT_NOT_FOUND);
8681
}
8782
try (FileInputStream fis = new FileInputStream(resultFile)) {
88-
byte[] openTofuResultData = fis.readAllBytes();
89-
OpenTofuResult openTofuResult =
90-
openTofuResultSerializer.deserialize(openTofuResultData);
91-
fis.close();
92-
deleteResultFileAndDirectory(new File(filePath));
93-
return ResponseEntity.ok(openTofuResult);
94-
} catch (IOException e) {
95-
log.error("Failed to retrieve OpenTofuResult for requestId: {}", requestId, e);
96-
throw new ResultAlreadyReturnedOrRequestIdInvalidException(
97-
"Failed to retrieve OpenTofuResult for requestId: " + requestId);
83+
OpenTofuResult terraformResult =
84+
openTofuResultSerializer.deserialize(fis.readAllBytes());
85+
deleteResultFileAndDirectory(resultFile);
86+
return ReFetchResult.builder()
87+
.requestId(requestId)
88+
.state(ReFetchState.OK)
89+
.openTofuResult(terraformResult)
90+
.build();
91+
} catch (Exception e) {
92+
String errorMsg =
93+
String.format("Failed to parse result file for requestId %s", requestId);
94+
return buildErrorResponse(requestId, errorMsg, ReFetchState.RESULT_PARSE_FAILED);
9895
}
9996
}
10097

101-
private boolean isDeployingInProgress(String requestId) {
102-
String workspace = scriptsHelper.buildTaskWorkspace(requestId);
103-
File targetFile;
104-
if (cleanWorkspaceAfterDeployment) {
105-
targetFile = new File(workspace);
106-
return targetFile.exists() && targetFile.isDirectory();
107-
} else {
108-
targetFile = new File(workspace, TF_LOCK_FILE_NAME);
109-
return targetFile.exists() && targetFile.isFile();
110-
}
98+
private ReFetchResult buildErrorResponse(
99+
UUID requestId, String errorMessage, ReFetchState state) {
100+
log.error(errorMessage);
101+
return ReFetchResult.builder()
102+
.requestId(requestId)
103+
.state(state)
104+
.errorMessage(errorMessage)
105+
.build();
106+
}
107+
108+
private boolean isValidResultFile(File file) {
109+
return file.exists() && file.isFile();
110+
}
111+
112+
private boolean isDeployingInProgress(UUID requestId) {
113+
String workspace = scriptsHelper.buildTaskWorkspace(requestId.toString());
114+
File targetFile = new File(workspace, TF_LOCK_FILE_NAME);
115+
return targetFile.exists() && targetFile.isFile();
111116
}
112117

113118
private void deleteResultFileAndDirectory(File resultFile) {
114119
try {
115120
deleteRecursively(resultFile);
116-
log.info("File folder deleted successfully: " + resultFile.getAbsolutePath());
121+
log.info("File folder deleted successfully: {}", resultFile.getAbsolutePath());
117122
} catch (Exception e) {
118-
log.error("An error occurred while deleting files: " + e.getMessage());
119-
e.printStackTrace();
123+
log.error("An error occurred while deleting files: {}", e.getMessage());
120124
}
121125
}
122126

@@ -129,10 +133,16 @@ private void deleteRecursively(File file) {
129133
}
130134
}
131135
}
132-
file.delete();
136+
if (file.delete()) {
137+
log.info("File deleted successfully: {}", file.getAbsolutePath());
138+
}
139+
}
140+
141+
private File getFilePath(UUID requestId) {
142+
return new File(failedCallbackStoreLocation + File.separator + requestId);
133143
}
134144

135-
private String getFilePath(UUID requestId) {
136-
return failedCallbackStoreLocation + File.separator + requestId.toString();
145+
private String getFileName(UUID requestId) {
146+
return requestId + TF_RESULT_FILE_SUFFIX;
137147
}
138148
}

Diff for: src/main/java/org/eclipse/xpanse/tofu/maker/utils/OpenTofuResultSerializer.java

+11-8
Original file line numberDiff line numberDiff line change
@@ -14,29 +14,32 @@
1414
@Component
1515
public class OpenTofuResultSerializer {
1616

17+
private final Serializer<byte[]> serializer;
18+
19+
/** Constructor to initialize the Serializer with OpenTofuResult class registered. */
20+
public OpenTofuResultSerializer() {
21+
final SerializerFoundation<?> foundation =
22+
SerializerFoundation.New().registerEntityTypes(OpenTofuResult.class);
23+
this.serializer = Serializer.Bytes(foundation);
24+
}
25+
1726
/**
18-
* serialize OpenTofuResult object.
27+
* Serialize OpenTofuResult object.
1928
*
2029
* @param result OpenTofuResult.
2130
* @return byte[].
2231
*/
2332
public byte[] serialize(OpenTofuResult result) {
24-
final SerializerFoundation<?> foundation =
25-
SerializerFoundation.New().registerEntityTypes(OpenTofuResult.class);
26-
Serializer<byte[]> serializer = Serializer.Bytes(foundation);
2733
return serializer.serialize(result);
2834
}
2935

3036
/**
31-
* deserialize OpenTofuResult object.
37+
* Deserialize OpenTofuResult object.
3238
*
3339
* @param data byte[].
3440
* @return OpenTofuResult.
3541
*/
3642
public OpenTofuResult deserialize(byte[] data) {
37-
final SerializerFoundation<?> foundation =
38-
SerializerFoundation.New().registerEntityTypes(OpenTofuResult.class);
39-
Serializer<byte[]> serializer = Serializer.Bytes(foundation);
4043
return serializer.deserialize(data);
4144
}
4245
}

Diff for: 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)