initial commit

This commit is contained in:
pratik
2025-10-20 11:07:35 -05:00
commit 0dae94011c
14 changed files with 1136 additions and 0 deletions

View File

@@ -0,0 +1,215 @@
package com.cfdeployer.service;
import com.cfdeployer.model.CfDeployRequest;
import com.cfdeployer.model.CfDeployResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.PosixFilePermission;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@Slf4j
@Service
@RequiredArgsConstructor
public class CfCliService {
@Value("${cf.cli.timeout:600}")
private long timeout;
@Value("${cf.cli.path:}")
private String cfCliPath;
public CfDeployResponse deployApplication(CfDeployRequest request, MultipartFile jarFile, MultipartFile manifest) {
Path tempDir = null;
try {
tempDir = Files.createTempDirectory("cf-deploy-");
log.info("Created temporary directory: {}", tempDir);
Path jarPath = tempDir.resolve(jarFile.getOriginalFilename());
Path manifestPath = tempDir.resolve("manifest.yml");
Files.copy(jarFile.getInputStream(), jarPath, StandardCopyOption.REPLACE_EXISTING);
Files.copy(manifest.getInputStream(), manifestPath, StandardCopyOption.REPLACE_EXISTING);
log.info("Copied JAR and manifest files to temporary directory");
StringBuilder output = new StringBuilder();
login(request, output);
pushApplication(request, tempDir, output);
logout(output);
log.info("Deployment completed successfully for app: {}", request.getAppName());
return CfDeployResponse.success(output.toString());
} catch (Exception e) {
log.error("Deployment failed for app: {}", request.getAppName(), e);
return CfDeployResponse.failure(e.getMessage(), e.toString());
} finally {
if (tempDir != null) {
cleanupTempDirectory(tempDir);
}
}
}
private void login(CfDeployRequest request, StringBuilder output) throws Exception {
log.info("Logging into Cloud Foundry at: {}", request.getApiEndpoint());
List<String> command = new ArrayList<>();
command.add(getCfCliExecutable());
command.add("login");
command.add("-a");
command.add(request.getApiEndpoint());
command.add("-u");
command.add(request.getUsername());
command.add("-p");
command.add(request.getPassword());
command.add("-o");
command.add(request.getOrganization());
command.add("-s");
command.add(request.getSpace());
if (Boolean.TRUE.equals(request.getSkipSslValidation())) {
command.add("--skip-ssl-validation");
}
executeCommand(command, output, true);
log.info("Successfully logged into Cloud Foundry");
}
private void pushApplication(CfDeployRequest request, Path workingDir, StringBuilder output) throws Exception {
log.info("Pushing application: {}", request.getAppName());
List<String> command = new ArrayList<>();
command.add(getCfCliExecutable());
command.add("push");
command.add(request.getAppName());
command.add("-f");
command.add("manifest.yml");
executeCommand(command, output, false, workingDir.toFile());
log.info("Successfully pushed application: {}", request.getAppName());
}
private void logout(StringBuilder output) throws Exception {
log.info("Logging out from Cloud Foundry");
List<String> command = new ArrayList<>();
command.add(getCfCliExecutable());
command.add("logout");
executeCommand(command, output, false);
log.info("Successfully logged out from Cloud Foundry");
}
private void executeCommand(List<String> command, StringBuilder output, boolean maskPassword) throws Exception {
executeCommand(command, output, maskPassword, null);
}
private void executeCommand(List<String> command, StringBuilder output, boolean maskPassword, File workingDir) throws Exception {
ProcessBuilder processBuilder = new ProcessBuilder(command);
if (workingDir != null) {
processBuilder.directory(workingDir);
}
processBuilder.redirectErrorStream(true);
if (maskPassword) {
List<String> maskedCommand = new ArrayList<>(command);
for (int i = 0; i < maskedCommand.size(); i++) {
if ("-p".equals(maskedCommand.get(i)) && i + 1 < maskedCommand.size()) {
maskedCommand.set(i + 1, "********");
}
}
log.debug("Executing command: {}", String.join(" ", maskedCommand));
} else {
log.debug("Executing command: {}", String.join(" ", command));
}
Process process = processBuilder.start();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
String line;
while ((line = reader.readLine()) != null) {
output.append(line).append("\n");
log.debug("CF CLI output: {}", line);
}
}
boolean finished = process.waitFor(timeout, TimeUnit.SECONDS);
if (!finished) {
process.destroyForcibly();
throw new RuntimeException("Command execution timed out after " + timeout + " seconds");
}
int exitCode = process.exitValue();
if (exitCode != 0) {
throw new RuntimeException("Command failed with exit code: " + exitCode);
}
}
private String getCfCliExecutable() throws IOException {
if (cfCliPath != null && !cfCliPath.isEmpty()) {
return cfCliPath;
}
String os = getOperatingSystem();
String executable = os.equals("windows") ? "cf.exe" : "cf";
String resourcePath = String.format("/cf-cli/%s/%s", os, executable);
File tempFile = File.createTempFile("cf-cli-", os.equals("windows") ? ".exe" : "");
tempFile.deleteOnExit();
try (var inputStream = getClass().getResourceAsStream(resourcePath)) {
if (inputStream == null) {
throw new IOException("CF CLI binary not found for OS: " + os);
}
Files.copy(inputStream, tempFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
}
if (!os.equals("windows")) {
Set<PosixFilePermission> perms = new HashSet<>();
perms.add(PosixFilePermission.OWNER_READ);
perms.add(PosixFilePermission.OWNER_WRITE);
perms.add(PosixFilePermission.OWNER_EXECUTE);
Files.setPosixFilePermissions(tempFile.toPath(), perms);
}
log.debug("Using CF CLI executable: {}", tempFile.getAbsolutePath());
return tempFile.getAbsolutePath();
}
private String getOperatingSystem() {
String osName = System.getProperty("os.name").toLowerCase();
if (osName.contains("win")) {
return "windows";
} else if (osName.contains("mac")) {
return "macos";
} else {
return "linux";
}
}
private void cleanupTempDirectory(Path tempDir) {
try {
FileUtils.deleteDirectory(tempDir.toFile());
log.debug("Cleaned up temporary directory: {}", tempDir);
} catch (IOException e) {
log.warn("Failed to clean up temporary directory: {}", tempDir, e);
}
}
}