Tanzu Changes

This commit is contained in:
pratik
2025-10-20 23:25:13 -05:00
parent d81e80f273
commit b7405c644b
4 changed files with 371 additions and 27 deletions

View File

@@ -11,10 +11,7 @@ import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
@RestController
@@ -60,6 +57,67 @@ public class CfDeployController {
}
}
@PostMapping("/apps")
public ResponseEntity<String> listApps(@RequestBody String requestJson) {
try {
log.info("Received request to list apps");
CfDeployRequest request = objectMapper.readValue(requestJson, CfDeployRequest.class);
String output = cfCliService.listApps(request);
return ResponseEntity.ok(output);
} catch (Exception e) {
log.error("Error listing apps", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("Failed to list apps: " + e.getMessage());
}
}
@PostMapping("/routes")
public ResponseEntity<String> listRoutes(@RequestBody String requestJson) {
try {
log.info("Received request to list routes");
CfDeployRequest request = objectMapper.readValue(requestJson, CfDeployRequest.class);
String output = cfCliService.listRoutes(request);
return ResponseEntity.ok(output);
} catch (Exception e) {
log.error("Error listing routes", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("Failed to list routes: " + e.getMessage());
}
}
@PostMapping("/app/{appName}")
public ResponseEntity<String> getAppDetails(
@PathVariable String appName,
@RequestBody String requestJson) {
try {
log.info("Received request to get details for app: {}", appName);
CfDeployRequest request = objectMapper.readValue(requestJson, CfDeployRequest.class);
String output = cfCliService.getAppDetails(request, appName);
return ResponseEntity.ok(output);
} catch (Exception e) {
log.error("Error getting app details for: {}", appName, e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("Failed to get app details: " + e.getMessage());
}
}
@PostMapping("/logs/{appName}")
public ResponseEntity<String> getAppLogs(
@PathVariable String appName,
@RequestParam(defaultValue = "true") boolean recent,
@RequestBody String requestJson) {
try {
log.info("Received request to get {} logs for app: {}", recent ? "recent" : "tail", appName);
CfDeployRequest request = objectMapper.readValue(requestJson, CfDeployRequest.class);
String output = cfCliService.getAppLogs(request, appName, recent);
return ResponseEntity.ok(output);
} catch (Exception e) {
log.error("Error getting logs for: {}", appName, e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("Failed to get app logs: " + e.getMessage());
}
}
private void validateFiles(MultipartFile jarFile, MultipartFile manifest) {
if (jarFile.isEmpty()) {
throw new IllegalArgumentException("JAR file is empty");

View File

@@ -39,28 +39,41 @@ public class CfCliService {
public CfDeployResponse deployApplication(CfDeployRequest request, MultipartFile jarFile, MultipartFile manifest) {
Path tempDir = null;
try {
log.info("=== Starting deployment for app: {} ===", request.getAppName());
log.info("Target: {}/{}/{}", request.getApiEndpoint(), request.getOrganization(), request.getSpace());
tempDir = Files.createTempDirectory("cf-deploy-");
log.info("Created temporary directory: {}", tempDir);
Path jarPath = tempDir.resolve(jarFile.getOriginalFilename());
Path manifestPath = tempDir.resolve("manifest.yml");
log.debug("Copying uploaded files - JAR: {}, Manifest: {}", jarFile.getOriginalFilename(), manifest.getOriginalFilename());
log.debug("JAR file size: {} bytes", jarFile.getSize());
log.debug("Manifest file size: {} bytes", manifest.getSize());
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");
log.info("Successfully copied JAR: {} ({} bytes) to {}", jarFile.getOriginalFilename(), jarFile.getSize(), jarPath);
log.info("Successfully copied manifest to {}", manifestPath);
log.debug("JAR absolute path: {}", jarPath.toAbsolutePath());
log.debug("JAR file exists: {}", Files.exists(jarPath));
log.debug("JAR file is readable: {}", Files.isReadable(jarPath));
StringBuilder output = new StringBuilder();
login(request, output);
pushApplication(request, tempDir, output);
pushApplication(request, tempDir, jarPath, output);
logout(output);
log.info("Deployment completed successfully for app: {}", request.getAppName());
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);
log.error("=== Deployment failed for app: {} ===", request.getAppName());
log.error("Error type: {}", e.getClass().getName());
log.error("Error message: {}", e.getMessage(), e);
return CfDeployResponse.failure(e.getMessage(), e.toString());
} finally {
if (tempDir != null) {
@@ -94,7 +107,7 @@ public class CfCliService {
log.info("Successfully logged into Cloud Foundry");
}
private void pushApplication(CfDeployRequest request, Path workingDir, StringBuilder output) throws Exception {
private void pushApplication(CfDeployRequest request, Path workingDir, Path jarPath, StringBuilder output) throws Exception {
log.info("Pushing application: {}", request.getAppName());
List<String> command = new ArrayList<>();
@@ -103,6 +116,8 @@ public class CfCliService {
command.add(request.getAppName());
command.add("-f");
command.add("manifest.yml");
command.add("-p");
command.add(jarPath.toAbsolutePath().toString());
executeCommand(command, output, false, workingDir.toFile());
log.info("Successfully pushed application: {}", request.getAppName());
@@ -127,6 +142,7 @@ public class CfCliService {
ProcessBuilder processBuilder = new ProcessBuilder(command);
if (workingDir != null) {
processBuilder.directory(workingDir);
log.debug("Working directory: {}", workingDir.getAbsolutePath());
}
processBuilder.redirectErrorStream(true);
@@ -137,50 +153,70 @@ public class CfCliService {
maskedCommand.set(i + 1, "********");
}
}
log.debug("Executing command: {}", String.join(" ", maskedCommand));
log.info("Executing CF CLI command: {}", String.join(" ", maskedCommand));
} else {
log.debug("Executing command: {}", String.join(" ", command));
log.info("Executing CF CLI command: {}", String.join(" ", command));
}
long startTime = System.currentTimeMillis();
Process process = processBuilder.start();
log.debug("Process started with PID: {}", process.pid());
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
String line;
int lineCount = 0;
while ((line = reader.readLine()) != null) {
lineCount++;
output.append(line).append("\n");
log.debug("CF CLI output: {}", line);
log.info("CF CLI: {}", line);
}
log.debug("Command produced {} lines of output", lineCount);
}
boolean finished = process.waitFor(timeout, TimeUnit.SECONDS);
long duration = System.currentTimeMillis() - startTime;
if (!finished) {
log.error("Command execution timed out after {} seconds", timeout);
process.destroyForcibly();
throw new RuntimeException("Command execution timed out after " + timeout + " seconds");
}
int exitCode = process.exitValue();
log.info("Command completed in {}ms with exit code: {}", duration, exitCode);
if (exitCode != 0) {
log.error("Command failed with exit code: {}", exitCode);
log.error("Command output:\n{}", output.toString());
throw new RuntimeException("Command failed with exit code: " + exitCode);
}
}
private String getCfCliExecutable() throws IOException {
if (cfCliPath != null && !cfCliPath.isEmpty()) {
log.info("Using custom CF CLI path: {}", cfCliPath);
return cfCliPath;
}
String os = getOperatingSystem();
String executable = os.equals("windows") ? "cf.exe" : "cf";
log.info("Detected operating system: {}", os);
log.debug("CF CLI executable name: {}", executable);
String resourcePath = String.format("/cf-cli/%s/%s", os, executable);
File tempFile = File.createTempFile("cf-cli-", os.equals("windows") ? ".exe" : "");
tempFile.deleteOnExit();
log.debug("Extracting CF CLI from resource path: {}", resourcePath);
try (var inputStream = getClass().getResourceAsStream(resourcePath)) {
if (inputStream == null) {
throw new IOException("CF CLI binary not found for OS: " + os);
log.error("CF CLI binary not found in resources for OS: {}. Expected path: {}", os, resourcePath);
throw new IOException("CF CLI binary not found for OS: " + os + " at path: " + resourcePath);
}
Files.copy(inputStream, tempFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
log.debug("CF CLI extracted to temporary file: {}", tempFile.getAbsolutePath());
}
if (!os.equals("windows")) {
@@ -189,14 +225,16 @@ public class CfCliService {
perms.add(PosixFilePermission.OWNER_WRITE);
perms.add(PosixFilePermission.OWNER_EXECUTE);
Files.setPosixFilePermissions(tempFile.toPath(), perms);
log.debug("Set executable permissions on CF CLI binary");
}
log.debug("Using CF CLI executable: {}", tempFile.getAbsolutePath());
log.info("Using CF CLI executable: {}", tempFile.getAbsolutePath());
return tempFile.getAbsolutePath();
}
private String getOperatingSystem() {
String osName = System.getProperty("os.name").toLowerCase();
log.debug("System OS name property: {}", osName);
if (osName.contains("win")) {
return "windows";
} else if (osName.contains("mac")) {
@@ -222,4 +260,97 @@ public class CfCliService {
log.warn("Failed to clean up temporary directory: {}", tempDir, e);
}
}
public String listApps(CfDeployRequest request) {
try {
log.info("Listing applications for org: {}, space: {}", request.getOrganization(), request.getSpace());
StringBuilder output = new StringBuilder();
login(request, output);
List<String> command = new ArrayList<>();
command.add(getCfCliExecutable());
command.add("apps");
executeCommand(command, output, false);
logout(output);
log.info("Successfully retrieved apps list");
return output.toString();
} catch (Exception e) {
log.error("Failed to list apps", e);
throw new RuntimeException("Failed to list apps: " + e.getMessage(), e);
}
}
public String listRoutes(CfDeployRequest request) {
try {
log.info("Listing routes for org: {}, space: {}", request.getOrganization(), request.getSpace());
StringBuilder output = new StringBuilder();
login(request, output);
List<String> command = new ArrayList<>();
command.add(getCfCliExecutable());
command.add("routes");
executeCommand(command, output, false);
logout(output);
log.info("Successfully retrieved routes list");
return output.toString();
} catch (Exception e) {
log.error("Failed to list routes", e);
throw new RuntimeException("Failed to list routes: " + e.getMessage(), e);
}
}
public String getAppDetails(CfDeployRequest request, String appName) {
try {
log.info("Getting details for app: {} in org: {}, space: {}", appName, request.getOrganization(), request.getSpace());
StringBuilder output = new StringBuilder();
login(request, output);
List<String> command = new ArrayList<>();
command.add(getCfCliExecutable());
command.add("app");
command.add(appName);
executeCommand(command, output, false);
logout(output);
log.info("Successfully retrieved app details for: {}", appName);
return output.toString();
} catch (Exception e) {
log.error("Failed to get app details for: {}", appName, e);
throw new RuntimeException("Failed to get app details: " + e.getMessage(), e);
}
}
public String getAppLogs(CfDeployRequest request, String appName, boolean recent) {
try {
log.info("Getting {} logs for app: {}", recent ? "recent" : "tail", appName);
StringBuilder output = new StringBuilder();
login(request, output);
List<String> command = new ArrayList<>();
command.add(getCfCliExecutable());
command.add("logs");
command.add(appName);
if (recent) {
command.add("--recent");
}
executeCommand(command, output, false);
logout(output);
log.info("Successfully retrieved logs for: {}", appName);
return output.toString();
} catch (Exception e) {
log.error("Failed to get logs for: {}", appName, e);
throw new RuntimeException("Failed to get app logs: " + e.getMessage(), e);
}
}
}