Skip to content

Commit

Permalink
add terraform plan generation methods
Browse files Browse the repository at this point in the history
  • Loading branch information
swaroopar committed Oct 5, 2023
1 parent 7e2a80c commit f00508b
Show file tree
Hide file tree
Showing 9 changed files with 204 additions and 46 deletions.
19 changes: 9 additions & 10 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
</parent>
<groupId>org.eclipse.xpanse.terraform.boot</groupId>
<artifactId>terraform-boot</artifactId>
<version>1.0.0</version>
<version>0.0.0-SNAPSHOT</version>
<name>terraform-boot</name>
<description>RESTful API Wrapper for Terraform</description>
<properties>
Expand All @@ -24,6 +24,7 @@
<checkstyle-maven-plugin.version>3.3.0</checkstyle-maven-plugin.version>
<logbook.version>3.1.0</logbook.version>
<nimbusds.oidc.sdk.version>10.7</nimbusds.oidc.sdk.version>
<lombok.version>1.18.28</lombok.version>
</properties>
<dependencies>
<dependency>
Expand All @@ -38,7 +39,6 @@
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
Expand Down Expand Up @@ -86,14 +86,13 @@
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import java.io.File;
import java.util.UUID;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.xpanse.terraform.boot.models.TerraformBootSystemStatus;
import org.eclipse.xpanse.terraform.boot.models.plan.TerraformPlan;
import org.eclipse.xpanse.terraform.boot.models.plan.TerraformPlanFromDirectoryRequest;
import org.eclipse.xpanse.terraform.boot.models.plan.TerraformPlanWithScriptsRequest;
import org.eclipse.xpanse.terraform.boot.models.request.TerraformDeployFromDirectoryRequest;
import org.eclipse.xpanse.terraform.boot.models.request.TerraformDeployWithScriptsRequest;
import org.eclipse.xpanse.terraform.boot.models.request.TerraformDestroyFromDirectoryRequest;
Expand Down Expand Up @@ -52,7 +53,7 @@ public class TerraformApiController {
@Autowired
public TerraformApiController(
@Qualifier("terraformDirectoryService")
TerraformDirectoryService terraformDirectoryService,
TerraformDirectoryService terraformDirectoryService,
TerraformScriptsService terraformScriptsService) {
this.terraformDirectoryService = terraformDirectoryService;
this.terraformScriptsService = terraformScriptsService;
Expand Down Expand Up @@ -101,9 +102,8 @@ public TerraformResult deploy(
description = "directory name where the Terraform module files exist.")
@PathVariable("module_directory") String moduleDirectory,
@Valid @RequestBody
TerraformDeployFromDirectoryRequest request) {
return terraformDirectoryService.deployFromDirectory(request,
moduleDirectory + File.separator + UUID.randomUUID());
TerraformDeployFromDirectoryRequest request) {
return terraformDirectoryService.deployFromDirectory(request, moduleDirectory);
}

/**
Expand All @@ -121,9 +121,8 @@ public TerraformResult destroy(
description = "directory name where the Terraform module files exist.")
@PathVariable("module_directory") String moduleDirectory,
@Valid @RequestBody
TerraformDestroyFromDirectoryRequest request) {
return terraformDirectoryService.destroyFromDirectory(request,
moduleDirectory + File.separator + UUID.randomUUID());
TerraformDestroyFromDirectoryRequest request) {
return terraformDirectoryService.destroyFromDirectory(request, moduleDirectory);
}

/**
Expand Down Expand Up @@ -196,4 +195,38 @@ public void asyncDestroyWithScripts(
@Valid @RequestBody TerraformAsyncDestroyFromDirectoryRequest asyncDestroyRequest) {
terraformScriptsService.asyncDestroyWithScripts(asyncDestroyRequest);
}

/**
* Method to get Terraform plan as a JSON string from a directory.
*
* @return Returns the terraform plan as a JSON string.
*/
@Tag(name = "Terraform", description = "APIs for running Terraform commands")
@Operation(description = "Get Terraform Plan as JSON string from a directory")
@PostMapping(value = "/plan/{module_directory}",
produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseStatus(HttpStatus.OK)
public TerraformPlan plan(
@Parameter(name = "module_directory",
description = "directory name where the Terraform module files exist.")
@PathVariable("module_directory") String moduleDirectory,
@Valid @RequestBody TerraformPlanFromDirectoryRequest request) {
return terraformDirectoryService.getTerraformPlanFromDirectory(request,
moduleDirectory);
}

/**
* Method to get Terraform plan as a JSON string from the list of script files provided.
*
* @return Returns the terraform plan as a JSON string.
*/
@Tag(name = "Terraform", description = "APIs for running Terraform commands")
@Operation(description =
"Get Terraform Plan as JSON string from the list of script files provided")
@PostMapping(value = "/plan", produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseStatus(HttpStatus.OK)
public TerraformPlan planWithScripts(
@Valid @RequestBody TerraformPlanWithScriptsRequest request) {
return terraformScriptsService.getTerraformPlanFromScripts(request);
}
}
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.plan;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Builder;
import lombok.Data;

/**
* Data model to represent terraform plan output.
*/
@Data
@Builder
public class TerraformPlan {

@NotNull
@Schema(description = "Terraform plan as a JSON string")
String plan;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* SPDX-License-Identifier: Apache-2.0
* SPDX-FileCopyrightText: Huawei Inc.
*/

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

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import java.util.HashMap;
import java.util.Map;
import lombok.Data;

/**
* Data model for the generating terraform plan.
*/
@Data
public class TerraformPlanFromDirectoryRequest {

@NotNull
@Schema(description = "Key-value pairs of variables that must be used to execute the "
+ "Terraform request.",
additionalProperties = Schema.AdditionalPropertiesValue.TRUE)
Map<String, Object> variables;

@Schema(description = "Key-value pairs of variables that must be injected as environment "
+ "variables to terraform process.",
additionalProperties = Schema.AdditionalPropertiesValue.TRUE)
Map<String, String> envVariables = new HashMap<>();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* SPDX-License-Identifier: Apache-2.0
* SPDX-FileCopyrightText: Huawei Inc.
*
*/

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

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import java.util.List;
import lombok.Data;

/**
* Data model for the generating terraform plan.
*/
@Data
public class TerraformPlanWithScriptsRequest extends TerraformPlanFromDirectoryRequest {

@NotNull
@Schema(description =
"List of terraform script files to be considered for generating terraform plan")
private List<String> scripts;

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
public class TerraformDeployWithScriptsRequest extends TerraformDeployFromDirectoryRequest {

@NotNull
@Schema(description = "List of script files for deployment requests deployed via scripts")
@Schema(description = "List of Terraform script files to be considered for deploying changes.")
private List<String> scripts;

}
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,14 @@ public class TerraformExecutor {
*/
@Autowired
public TerraformExecutor(SystemCmd systemCmd,
@Value("${terraform.root.module.directory}")
String moduleParentDirectoryPath,
@Value("${log.terraform.stdout.stderr:true}")
boolean isStdoutStdErrLoggingEnabled,
@Value("${terraform.binary.location}")
String customTerraformBinary,
@Value("${terraform.log.level}")
String terraformLogLevel
@Value("${terraform.root.module.directory}")
String moduleParentDirectoryPath,
@Value("${log.terraform.stdout.stderr:true}")
boolean isStdoutStdErrLoggingEnabled,
@Value("${terraform.binary.location}")
String customTerraformBinary,
@Value("${terraform.log.level}")
String terraformLogLevel
) {
if (moduleParentDirectoryPath.isBlank() || moduleParentDirectoryPath.isEmpty()) {
this.moduleParentDirectoryPath =
Expand All @@ -84,7 +84,7 @@ public TerraformExecutor(SystemCmd systemCmd,
* Terraform executes init, plan and destroy commands.
*/
public SystemCmdResult tfDestroy(Map<String, Object> variables,
Map<String, String> envVariables, String moduleDirectory) {
Map<String, String> envVariables, String moduleDirectory) {
tfPlan(variables, envVariables, moduleDirectory);
SystemCmdResult applyResult =
tfDestroyCommand(variables, envVariables, getModuleFullPath(moduleDirectory));
Expand All @@ -100,7 +100,7 @@ public SystemCmdResult tfDestroy(Map<String, Object> variables,
* Terraform executes init, plan and apply commands.
*/
public SystemCmdResult tfApply(Map<String, Object> variables, Map<String, String> envVariables,
String moduleDirectory) {
String moduleDirectory) {
tfPlan(variables, envVariables, moduleDirectory);
SystemCmdResult applyResult =
tfApplyCommand(variables, envVariables, getModuleFullPath(moduleDirectory));
Expand All @@ -116,7 +116,7 @@ public SystemCmdResult tfApply(Map<String, Object> variables, Map<String, String
* Terraform executes init and plan commands.
*/
public SystemCmdResult tfPlan(Map<String, Object> variables, Map<String, String> envVariables,
String moduleDirectory) {
String moduleDirectory) {
tfInit(moduleDirectory);
SystemCmdResult planResult =
tfPlanCommand(variables, envVariables, getModuleFullPath(moduleDirectory));
Expand All @@ -128,6 +128,32 @@ public SystemCmdResult tfPlan(Map<String, Object> variables, Map<String, String>
return planResult;
}

/**
* Method to execute terraform plan and get the plan as a json string.
*/
public String getTerraformPlanAsJson(Map<String, Object> variables,
Map<String, String> envVariables,
String moduleDirectory) {
tfInit(moduleDirectory);
SystemCmdResult tfPlanResult = executeWithVariables(
new StringBuilder(
getTerraformCommand("plan -input=false -no-color --out tfplan.binary ")),
variables, envVariables, getModuleFullPath(moduleDirectory));
if (!tfPlanResult.isCommandSuccessful()) {
log.error("TFExecutor.tfPlan failed.");
throw new TerraformExecutorException("TFExecutor.tfPlan failed.",
tfPlanResult.getCommandStdError());
}
SystemCmdResult planJsonResult = execute(getTerraformCommand("show -json tfplan.binary"),
getModuleFullPath(moduleDirectory), envVariables);
if (!planJsonResult.isCommandSuccessful()) {
log.error("Reading Terraform plan as JSON failed.");
throw new TerraformExecutorException("Reading Terraform plan as JSON failed.",
planJsonResult.getCommandStdError());
}
return planJsonResult.getCommandStdOutput();
}

/**
* Terraform executes the init command.
*/
Expand Down Expand Up @@ -165,7 +191,7 @@ public String getModuleFullPath(String moduleDirectory) {
/**
* Executes terraform init command.
*
* @return Returns result of SystemCmd executes.
* @return Returns result of SystemCmd executed.
*/
private SystemCmdResult tfInitCommand(String workspace) {
return execute(getTerraformCommand("init -no-color"),
Expand All @@ -175,7 +201,7 @@ private SystemCmdResult tfInitCommand(String workspace) {
/**
* Executes terraform validate command.
*
* @return Returns result of SystemCmd executes.
* @return Returns result of SystemCmd executed.
*/
private SystemCmdResult tfValidateCommand(String workspace) {
return execute(getTerraformCommand("validate -json -no-color"),
Expand All @@ -185,10 +211,10 @@ private SystemCmdResult tfValidateCommand(String workspace) {
/**
* Executes terraform plan command.
*
* @return Returns result of SystemCmd executes.
* @return Returns result of SystemCmd executed.
*/
private SystemCmdResult tfPlanCommand(Map<String, Object> variables,
Map<String, String> envVariables, String workspace) {
Map<String, String> envVariables, String workspace) {
return executeWithVariables(
new StringBuilder(getTerraformCommand("plan -input=false -no-color ")),
variables, envVariables, workspace);
Expand All @@ -197,10 +223,10 @@ private SystemCmdResult tfPlanCommand(Map<String, Object> variables,
/**
* Executes terraform apply command.
*
* @return Returns result of SystemCmd executes.
* @return Returns result of SystemCmd executed.
*/
private SystemCmdResult tfApplyCommand(Map<String, Object> variables,
Map<String, String> envVariables, String workspace) {
Map<String, String> envVariables, String workspace) {
return executeWithVariables(
new StringBuilder(
getTerraformCommand("apply -auto-approve -input=false -no-color ")),
Expand All @@ -210,10 +236,10 @@ private SystemCmdResult tfApplyCommand(Map<String, Object> variables,
/**
* Executes terraform destroy command.
*
* @return Returns result of SystemCmd executes.
* @return Returns result of SystemCmd executed.
*/
private SystemCmdResult tfDestroyCommand(Map<String, Object> variables,
Map<String, String> envVariables, String workspace) {
Map<String, String> envVariables, String workspace) {
return executeWithVariables(
new StringBuilder("terraform destroy -auto-approve -input=false -no-color "),
variables, envVariables, workspace);
Expand All @@ -222,12 +248,12 @@ private SystemCmdResult tfDestroyCommand(Map<String, Object> variables,
/**
* Executes terraform commands with parameters.
*
* @return Returns result of SystemCmd executes.
* @return Returns result of SystemCmd executed.
*/
private SystemCmdResult executeWithVariables(StringBuilder command,
Map<String, Object> variables,
Map<String, String> envVariables,
String workspace) {
Map<String, Object> variables,
Map<String, String> envVariables,
String workspace) {
createVariablesFile(variables, workspace);
command.append(" -var-file=");
command.append(VARS_FILE_NAME);
Expand All @@ -242,7 +268,7 @@ private SystemCmdResult executeWithVariables(StringBuilder command,
* @return SystemCmdResult
*/
private SystemCmdResult execute(String cmd, String workspace,
@NonNull Map<String, String> envVariables) {
@NonNull Map<String, String> envVariables) {
envVariables.putAll(getTerraformLogConfig());
return this.systemCmd.execute(cmd, workspace, this.isStdoutStdErrLoggingEnabled,
envVariables);
Expand Down
Loading

0 comments on commit f00508b

Please sign in to comment.