Skip to content

Commit

Permalink
Initial Tofu Support (#43)
Browse files Browse the repository at this point in the history
  • Loading branch information
alfespa17 authored Jan 16, 2024
1 parent 5b8b991 commit 2922c00
Show file tree
Hide file tree
Showing 11 changed files with 165 additions and 13 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,18 @@ public class SpringStarterSampleApp implements CommandLineRunner {
}
```

### OpenTofu Support

When using with opentofu you need to use the terraformProcessData like the following:

```java
TerraformProcessData terraformProcessData = TerraformProcessData.builder()
.terraformVersion("1.6.0")
.workingDirectory(new File("/some/terraform/path"))
.tofu(true)
.build();
```

### Custom Terraform Releases URL

You can customize the URL from where you download your terraform binary.
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<revision>0.11.2</revision>
<revision>0.12.0</revision>
<sonar.organization>azbuilder</sonar.organization>
<sonar.host.url>https://sonarcloud.io</sonar.host.url>
<maven.deploy.skip>true</maven.deploy.skip>
Expand Down
2 changes: 1 addition & 1 deletion terraform-client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<maven-source-plugin.version>3.3.0</maven-source-plugin.version>
<maven-javadoc-plugin.version>3.6.2</maven-javadoc-plugin.version>
<maven-gpg-plugin.version>3.1.0</maven-gpg-plugin.version>
<revision>0.11.2</revision>
<revision>0.12.0</revision>
<maven.deploy.skip>false</maven.deploy.skip>
<commons-io.version>2.15.0</commons-io.version>
<maven-artifact.version>3.9.5</maven-artifact.version>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ private ProcessLauncher getTerraformLauncher(TerraformCommand command) throws IO

private ProcessLauncher getTerraformLauncher(TerraformProcessData terraformProcessData, Consumer<String> outputListener, Consumer<String> errorListener, TerraformCommand command) throws IOException {
TerraformDownloader terraformDownloader = createTerraformDownloader();
String terraformPath = terraformDownloader.downloadTerraformVersion(terraformProcessData.getTerraformVersion());
String terraformPath = terraformProcessData.isTofu() ? terraformDownloader.downloadTofuVersion(terraformProcessData.getTerraformVersion()) : terraformDownloader.downloadTerraformVersion(terraformProcessData.getTerraformVersion());

if (terraformProcessData.sshFile != null && command.equals(TerraformCommand.init)) {
return getTerraformInitWithSSH(terraformPath, terraformProcessData, outputListener, errorListener);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,25 @@
public class TerraformDownloader {

private static final String TERRAFORM_DOWNLOAD_DIRECTORY = "/.terraform-spring-boot/download/";
private static final String TOFU_DOWNLOAD_DIRECTORY = "/.terraform-spring-boot/download/tofu/";
private static final String TERRAFORM_DIRECTORY = "/.terraform-spring-boot/terraform/";

private static final String TOFU_DIRECTORY = "/.terraform-spring-boot/tofu/";
private static final String TEMP_DIRECTORY = "/.terraform-spring-boot/";
public static final String TERRAFORM_RELEASES_URL = "https://releases.hashicorp.com/terraform/index.json";

private TerraformResponse terraformReleases;
private File terraformDownloadDirectory;

private File tofuDownloadDirectory;
private File terraformDirectory;
private String userHomeDirectory;

public TerraformDownloader() {
try {
log.info("Initialize TerraformDownloader using default URL");
log.info("Initialize Terraform and Tofu Downloader using default URL");
createDownloadTempDirectory();
createDownloadTofuTempDirectory();
getTerraformReleases(TERRAFORM_RELEASES_URL);
} catch (IOException ex) {
log.error(ex.getMessage());
Expand All @@ -48,6 +53,7 @@ public TerraformDownloader(String terraformReleasesUrl) {

try {
createDownloadTempDirectory();
createDownloadTofuTempDirectory();
getTerraformReleases(terraformReleasesUrl);
} catch (IOException ex) {
log.error(ex.getMessage());
Expand Down Expand Up @@ -75,6 +81,27 @@ private void createDownloadTempDirectory() throws IOException {
log.info("Validate/Create terraform directory: {}", terrafomVersionPath);
}

private void createDownloadTofuTempDirectory() throws IOException {
this.userHomeDirectory = FileUtils.getUserDirectoryPath();
log.info("User Home Directory for tofu download: {}", this.userHomeDirectory);

String tofuDownloadPath = userHomeDirectory.concat(
FilenameUtils.separatorsToSystem(
TOFU_DOWNLOAD_DIRECTORY
));
this.tofuDownloadDirectory = new File(tofuDownloadPath);
FileUtils.forceMkdir(this.tofuDownloadDirectory);
log.info("Validate/Create tofu download temp directory: {}", tofuDownloadPath);

String tofuVersionPath = userHomeDirectory.concat(
FilenameUtils.separatorsToSystem(
TOFU_DIRECTORY
));
this.terraformDirectory = new File(tofuVersionPath);
FileUtils.forceMkdir(this.terraformDirectory);
log.info("Validate/Create tofu directory: {}", tofuVersionPath);
}

private void getTerraformReleases(String terraformReleasesUrl) throws IOException {
log.info("Downloading terraform releases list");

Expand Down Expand Up @@ -168,8 +195,69 @@ public String downloadTerraformVersion(String terraformVersion) throws IOExcepti
return terraformFilePath;
}


public String downloadTofuVersion(String tofuVersion) throws IOException {
log.info("Downloading tofu version {} architecture {} Type {}", tofuVersion, SystemUtils.OS_ARCH, SystemUtils.OS_NAME);
// "https://github.com/opentofu/opentofu/releases/download/v1.6.0/tofu_1.6.0_windows_386.zip"
// "https://github.com/opentofu/opentofu/releases/download/v1.6.0/tofu_1.6.0_linux_amd64.zip"
// "https://github.com/opentofu/opentofu/releases/download/v1.6.0/tofu_1.6.0_darwin_amd64.zip"
String defaultDownloadUrl = "https://github.com/opentofu/opentofu/releases/download/v%s/tofu_%s_%s_%s.zip";
String defaultFileName = "tofu_%s_%s_%s.zip";

String tofuZipReleaseURL = String.format(defaultDownloadUrl, tofuVersion, tofuVersion, getOs(), SystemUtils.OS_ARCH );
String tofuFileName = String.format(defaultFileName, tofuVersion, getOs(), SystemUtils.OS_ARCH );
String tofuFilePath = "";
if (tofuVersion != null) {
String fileName = tofuFileName;

if (!FileUtils.directoryContains(this.tofuDownloadDirectory, new File(
this.userHomeDirectory.concat(
FilenameUtils.separatorsToSystem(
TOFU_DOWNLOAD_DIRECTORY.concat("/").concat(fileName)
))))) {

log.info("Downloading Tofu from: {}", tofuZipReleaseURL);
try {
File tofuZipFile = new File(
this.userHomeDirectory.concat(
FilenameUtils.separatorsToSystem(
TOFU_DOWNLOAD_DIRECTORY.concat(fileName)
)));

FileUtils.copyURLToFile(new URL(tofuZipReleaseURL), tofuZipFile);

tofuFilePath = unzipTofuVersion(tofuVersion, tofuZipFile);
} catch (IOException exception) {
throw new IOException("Unable to download tofu ".concat(tofuZipReleaseURL));
}
} else {
log.info("{} tofu already exists", fileName);

return this.userHomeDirectory.concat(
FilenameUtils.separatorsToSystem(
TOFU_DIRECTORY.concat(tofuVersion.concat("/").concat("tofu"))
)
);
}
} else {
throw new IllegalArgumentException("Invalid Tofu Version");
}

return tofuFilePath;
}

public String getOs(){
if (SystemUtils.IS_OS_LINUX)
return "linux";
if (SystemUtils.IS_OS_MAC)
return "darwin";
if (SystemUtils.IS_OS_WINDOWS)
return "windows";
return "linux";
}

private String unzipTerraformVersion(String terraformVersion, File terraformZipFile) throws IOException {
createTerraformVersionDirectory(terraformVersion);
createVersionDirectory(terraformVersion, TERRAFORM_DIRECTORY);
String newFilePath = null;
try (ZipInputStream zis = new ZipInputStream(new FileInputStream(terraformZipFile))) {
ZipEntry zipEntry = zis.getNextEntry();
Expand Down Expand Up @@ -215,11 +303,61 @@ private String unzipTerraformVersion(String terraformVersion, File terraformZipF
return newFilePath;
}

private void createTerraformVersionDirectory(String terraformVersion) throws IOException {
private String unzipTofuVersion(String tofuVersion, File tofuZipFile) throws IOException {
createVersionDirectory(tofuVersion, TOFU_DIRECTORY);
String newFilePath = null;
try (ZipInputStream zis = new ZipInputStream(new FileInputStream(tofuZipFile))) {
ZipEntry zipEntry = zis.getNextEntry();

byte[] buffer = new byte[1024];
while (zipEntry != null) {
newFilePath = this.userHomeDirectory.concat(
FilenameUtils.separatorsToSystem(
TOFU_DIRECTORY.concat(tofuVersion.concat("/").concat(zipEntry.getName()))
)
);
log.info("Unzip Tofu files: {}", newFilePath);
File newTofuFile = new File(newFilePath);
if (zipEntry.isDirectory()) {
if (!newTofuFile.isDirectory() && !newTofuFile.mkdirs()) {
throw new IOException("Failed to create directory for" + newTofuFile);
}
} else {
File parent = newTofuFile.getParentFile();
if (!parent.isDirectory() && !parent.mkdirs()) {
throw new IOException("Failed to create directory for" + parent);
}

try (FileOutputStream file = new FileOutputStream(newTofuFile)) {
int len;
while ((len = zis.read(buffer)) > 0) {
file.write(buffer, 0, len);
}
}

if (SystemUtils.IS_OS_LINUX || SystemUtils.IS_OS_MAC) {
File updateAccess = new File(newFilePath);
if (updateAccess.setExecutable(true, true))
log.info("Tofu setExecutable successful");
else
log.error("Tofu setExecutable successful");
}
}
zipEntry = zis.getNextEntry();
}
zis.closeEntry();
}
return this.userHomeDirectory.concat(
FilenameUtils.separatorsToSystem(
TOFU_DIRECTORY.concat(tofuVersion.concat("/").concat("tofu"))
));
}

private void createVersionDirectory(String version, String directoryPath) throws IOException {
File terraformVersionDirectory = new File(
userHomeDirectory.concat(
FilenameUtils.separatorsToSystem(
TERRAFORM_DIRECTORY.concat(terraformVersion)
directoryPath.concat(version)
)));
FileUtils.forceMkdir(terraformVersionDirectory);
}
Expand Down Expand Up @@ -253,4 +391,4 @@ class TerraformVersion {
private String shasums_signature;
private List<String> shasums_signatures;
private List<TerraformBuild> builds;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ public class TerraformProcessData {
boolean refresh = true;
@Builder.Default
boolean refreshOnly = false;
@Builder.Default
boolean tofu = false;
@Singular Map<String, String> terraformVariables;
@Singular Map<String, String> terraformEnvironmentVariables;
}
2 changes: 1 addition & 1 deletion terraform-spring-boot-autoconfigure/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<maven-source-plugin.version>3.3.0</maven-source-plugin.version>
<maven-javadoc-plugin.version>3.6.2</maven-javadoc-plugin.version>
<maven-gpg-plugin.version>3.1.0</maven-gpg-plugin.version>
<revision>0.11.2</revision>
<revision>0.12.0</revision>
<maven.deploy.skip>false</maven.deploy.skip>
<lombok.version>1.18.30</lombok.version>
<maven.compiler.source>11</maven.compiler.source>
Expand Down
2 changes: 1 addition & 1 deletion terraform-spring-boot-samples/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<revision>0.11.2</revision>
<revision>0.12.0</revision>
<maven.deploy.skip>true</maven.deploy.skip>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.deploy.skip>true</maven.deploy.skip>
<revision>0.11.2</revision>
<revision>0.12.0</revision>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.deploy.skip>true</maven.deploy.skip>
<revision>0.11.2</revision>
<revision>0.12.0</revision>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
Expand Down
2 changes: 1 addition & 1 deletion terraform-spring-boot-starter/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<maven-source-plugin.version>3.3.0</maven-source-plugin.version>
<maven-javadoc-plugin.version>3.6.2</maven-javadoc-plugin.version>
<maven-gpg-plugin.version>3.1.0</maven-gpg-plugin.version>
<revision>0.11.2</revision>
<revision>0.12.0</revision>
<maven.deploy.skip>false</maven.deploy.skip>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
Expand Down

0 comments on commit 2922c00

Please sign in to comment.