Skip to content

Commit

Permalink
terraform-boot - Enable async processing of deploy and destroy API me…
Browse files Browse the repository at this point in the history
…thods
  • Loading branch information
WangLiNaruto committed Aug 16, 2023
1 parent b353f65 commit 46b1975
Show file tree
Hide file tree
Showing 12 changed files with 354 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.scheduling.annotation.EnableAsync;

/**
* Main entry class to terraform-boot. This class can be directly executed to start the server.
*/
@EnableAsync
@SpringBootApplication(exclude = {SecurityAutoConfiguration.class})
public class TerraformBootApplication {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
import org.eclipse.xpanse.terraform.boot.models.enums.HealthStatus;
import org.eclipse.xpanse.terraform.boot.models.request.TerraformDeployRequest;
import org.eclipse.xpanse.terraform.boot.models.request.TerraformDestroyRequest;
import org.eclipse.xpanse.terraform.boot.models.request.async.TerraformAsyncDeployRequest;
import org.eclipse.xpanse.terraform.boot.models.request.async.TerraformAsyncDestroyRequest;
import org.eclipse.xpanse.terraform.boot.models.response.TerraformResult;
import org.eclipse.xpanse.terraform.boot.models.validation.TerraformValidationResult;
import org.eclipse.xpanse.terraform.boot.terraform.TerraformExecutor;
Expand Down Expand Up @@ -100,7 +102,7 @@ public TerraformResult deploy(
* @return Returns the status of the resources destroy.
*/
@Tag(name = "Terraform", description = "APIs for running Terraform commands")
@Operation(description = "Validate the Terraform modules")
@Operation(description = "Destroy the Terraform modules")
@DeleteMapping(value = "/destroy/{module_directory}",
produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseStatus(HttpStatus.OK)
Expand All @@ -111,4 +113,38 @@ public TerraformResult destroy(
@Valid @RequestBody TerraformDestroyRequest terraformDestroyRequest) {
return this.terraformExecutor.destroy(terraformDestroyRequest, moduleDirectory);
}

/**
* Method to async deploy resources requested in a workspace.
*
*/
@Tag(name = "Terraform", description = "APIs for running Terraform commands")
@Operation(description = "async deploy resources via Terraform")
@PostMapping(value = "/deploy/async/{module_directory}", produces =
MediaType.APPLICATION_JSON_VALUE)
@ResponseStatus(HttpStatus.ACCEPTED)
public void asyncDeploy(
@Parameter(name = "module_directory",
description = "directory name where the Terraform module files exist.")
@PathVariable("module_directory") String moduleDirectory,
@Valid @RequestBody TerraformAsyncDeployRequest asyncDeployRequest) {
terraformExecutor.asyncDeploy(asyncDeployRequest, moduleDirectory);
}

/**
* Method to async destroy resources requested in a workspace.
*
*/
@Tag(name = "Terraform", description = "APIs for running Terraform commands")
@Operation(description = "Async destroy the Terraform modules")
@DeleteMapping(value = "/destroy/async/{module_directory}",
produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseStatus(HttpStatus.ACCEPTED)
public void asyncDestroy(
@Parameter(name = "module_directory",
description = "directory name where the Terraform module files exist.")
@PathVariable("module_directory") String moduleDirectory,
@Valid @RequestBody TerraformAsyncDestroyRequest asyncDestroyRequest) {
terraformExecutor.asyncDestroy(asyncDestroyRequest, moduleDirectory);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* SPDX-License-Identifier: Apache-2.0
* SPDX-FileCopyrightText: Huawei Inc.
*
*/

package org.eclipse.xpanse.terraform.boot.async;

import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import org.slf4j.MDC;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

/**
* Overwrite the thread pool to solve the problem that the traceId will be lost in the process of
* printing the log.
*/
public class ServiceThreadPoolTaskExecutor extends ThreadPoolTaskExecutor {

public ServiceThreadPoolTaskExecutor() {
super();
}

@Override
public void execute(Runnable task) {
super.execute(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()));
}


@Override
public <T> Future<T> submit(Callable<T> task) {
return super.submit(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()));
}

@Override
public Future<?> submit(Runnable task) {
return super.submit(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* SPDX-License-Identifier: Apache-2.0
* SPDX-FileCopyrightText: Huawei Inc.
*
*/

package org.eclipse.xpanse.terraform.boot.async;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
* Customize the thread pool. Define ThreadPoolTaskExecutor named taskExecutor to replace @Async's
* default thread pool.
*/
@Configuration
public class TaskConfiguration {

private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();

/**
* Define ThreadPoolTaskExecutor named taskExecutor.
*
* @return executor
*/
@Bean("taskExecutor")
public Executor taskExecutor() {
ServiceThreadPoolTaskExecutor
executor = new ServiceThreadPoolTaskExecutor();
executor.setCorePoolSize(CPU_COUNT * 2);
executor.setMaxPoolSize(20);
executor.setQueueCapacity(200);
executor.setKeepAliveSeconds(300);
executor.setThreadNamePrefix("thread-pool-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* SPDX-License-Identifier: Apache-2.0
* SPDX-FileCopyrightText: Huawei Inc.
*
*/

package org.eclipse.xpanse.terraform.boot.async;

import java.util.Map;
import java.util.concurrent.Callable;
import org.slf4j.MDC;

/**
* Bean to get mdc logging info.
*/
public final class ThreadMdcUtil {

/**
* When the parent thread submits a callable task to the thread pool, it copies the data in its
* own MDC to the child thread.
*
* @param callable callable task
* @param context context
* @param <T> return object type
* @return T
*/
public static <T> Callable<T> wrap(final Callable<T> callable,
final Map<String, String> context) {
return new Callable<>() {
@Override
public T call() throws Exception {
if (context == null) {
MDC.clear();
} else {
MDC.setContextMap(context);
}
try {
return callable.call();
} finally {
MDC.clear();
}
}
};
}

/**
* When the parent thread submits a runnable task to the thread pool, it copies the data in its
* own MDC to the child thread.
*
* @param runnable runnable task
* @param context context
* @return thread task
*/
public static Runnable wrap(final Runnable runnable, final Map<String, String> context) {
return () -> {
if (context == null) {
MDC.clear();
} else {
MDC.setContextMap(context);
}
try {
runnable.run();
} finally {
MDC.clear();
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* SPDX-License-Identifier: Apache-2.0
* SPDX-FileCopyrightText: Huawei Inc.
*/

package org.eclipse.xpanse.terraform.boot.config;


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

/**
* Configuration class for RestTemplate.
*/
@Configuration
public class RestTemplateConfig {

/**
* Create RestTemplate to IOC.
*/
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
return new RestTemplate(factory);
}

/**
* Create ClientHttpRequestFactory to IOC.
*/
@Bean
public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setConnectTimeout(15000);
factory.setReadTimeout(5000);
return factory;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* SPDX-License-Identifier: Apache-2.0
* SPDX-FileCopyrightText: Huawei Inc.
*/

package org.eclipse.xpanse.terraform.boot.models.enums;

/**
* The permission type class when calling back.
*/
public enum AuthType {
NONE,
OAUTH2;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,12 @@
* SPDX-FileCopyrightText: Huawei Inc.
*/

package org.eclipse.xpanse.terraform.boot.api.exceptions;
package org.eclipse.xpanse.terraform.boot.models.exceptions;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.xpanse.terraform.boot.models.exceptions.TerraformExecutorException;
import org.eclipse.xpanse.terraform.boot.models.exceptions.UnsupportedEnumValueException;
import org.eclipse.xpanse.terraform.boot.models.response.Response;
import org.eclipse.xpanse.terraform.boot.models.response.ResultType;
import org.springframework.http.HttpStatus;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* SPDX-License-Identifier: Apache-2.0
* SPDX-FileCopyrightText: Huawei Inc.
*/

package org.eclipse.xpanse.terraform.boot.models.request.async;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.eclipse.xpanse.terraform.boot.models.request.TerraformDeployRequest;

/**
* Data model for the terraform async deploy requests.
*/
@Data
public class TerraformAsyncDeployRequest extends TerraformDeployRequest {

@NotNull
@Schema(description = "Configuration information of webhook.")
private WebhookConfig webhookConfig;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* SPDX-License-Identifier: Apache-2.0
* SPDX-FileCopyrightText: Huawei Inc.
*/

package org.eclipse.xpanse.terraform.boot.models.request.async;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.eclipse.xpanse.terraform.boot.models.request.TerraformDestroyRequest;

/**
* Data model for the terraform async destroy requests.
*/
@Data
public class TerraformAsyncDestroyRequest extends TerraformDestroyRequest {

@NotNull
@Schema(description = "Configuration information of webhook.")
private WebhookConfig webhookConfig;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* SPDX-License-Identifier: Apache-2.0
* SPDX-FileCopyrightText: Huawei Inc.
*/

package org.eclipse.xpanse.terraform.boot.models.request.async;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.eclipse.xpanse.terraform.boot.models.enums.AuthType;

/**
* Configuration information class of webhook.
*/
@Data
public class WebhookConfig {

@NotNull
@Schema(description = "Callback address after deployment/destroy is completed.")
private String url;

@NotNull
@Schema(description = "The permission type when calling back.")
private AuthType authType;
}
Loading

0 comments on commit 46b1975

Please sign in to comment.