Tanzu Changes
This commit is contained in:
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user