Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

resolve conflict #100

Merged
merged 2 commits into from
Nov 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"java.compile.nullAnalysis.mode": "automatic",
"java.dependency.packagePresentation": "hierarchical"
"java.dependency.packagePresentation": "hierarchical",
"java.configuration.updateBuildConfiguration": "automatic"
}
17 changes: 17 additions & 0 deletions applicationFE/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,11 @@ dependencies {
implementation 'io.kubernetes:client-java-api:20.0.0'
implementation 'io.kubernetes:client-java-extended:20.0.0'

implementation 'com.github.docker-java:docker-java:3.3.0'
implementation 'com.github.docker-java:docker-java-transport-httpclient5:3.3.0'

implementation 'io.github.cdancy:jenkins-rest:1.0.1:all'


}

Expand Down
3 changes: 3 additions & 0 deletions src/main/java/kr/co/mcmp/ApplicationManagerApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.scheduling.annotation.EnableScheduling;

import springfox.documentation.swagger2.annotations.EnableSwagger2;

import java.io.UnsupportedEncodingException;
Expand All @@ -11,6 +13,7 @@
@EnableSwagger2
@SpringBootApplication
@EnableFeignClients
@EnableScheduling
public class ApplicationManagerApplication {

public static void main(String[] args) throws GeneralSecurityException, UnsupportedEncodingException {
Expand Down
152 changes: 124 additions & 28 deletions src/main/java/kr/co/mcmp/ape/cbtumblebug/api/CbtumblebugRestApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClientException;
import org.springframework.web.util.UriComponentsBuilder;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import kr.co.mcmp.ape.cbtumblebug.dto.K8sClusterDto;
Expand All @@ -25,8 +28,9 @@
import kr.co.mcmp.ape.cbtumblebug.dto.MciResponse;
import kr.co.mcmp.ape.cbtumblebug.dto.NamespaceDto;
import kr.co.mcmp.ape.cbtumblebug.dto.NamespaceResponse;
import kr.co.mcmp.ape.cbtumblebug.dto.MciAccessInfoDto;
import kr.co.mcmp.ape.cbtumblebug.dto.Spec;
import kr.co.mcmp.ape.cbtumblebug.dto.VmDto;
import kr.co.mcmp.ape.cbtumblebug.dto.VmAccessInfo;
import kr.co.mcmp.ape.cbtumblebug.exception.CbtumblebugException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -50,6 +54,10 @@ public class CbtumblebugRestApi {

private final CbtumblebugRestClient restClient;

private boolean isTumblebugReady = false;
private long lastCheckTime = 0;
private static final long CHECK_INTERVAL = 60000; // 1 minute

private HttpHeaders createCommonHeaders() {
HttpHeaders headers = new HttpHeaders();
String auth = cbtumblebugId + ":" + cbtumblebugPass;
Expand All @@ -66,7 +74,7 @@ private String createApiUrl(String endpoint) {

return apiUrl;
}

/*
public boolean checkTumblebug() {
log.info("Checking if Tumblebug is ready");
String apiUrl = createApiUrl("/tumblebug/readyz");
Expand All @@ -79,16 +87,104 @@ public boolean checkTumblebug() {
log.error("Tumblebug connection failed", e);
return false;
}
}
}


private <T> T executeWithConnectionCheck(String operationName, Supplier<T> apiCall) {
if (!checkTumblebug()) {
log.error("Tumblebug에 연결할 수 없습니다. {} 작업을 수행할 수 없습니다.", operationName);
throw new CbtumblebugException("Tumblebug 연결 실패");
}
return apiCall.get();
}
*/

public boolean checkTumblebug() {
long currentTime = System.currentTimeMillis();
if (currentTime - lastCheckTime > CHECK_INTERVAL || !isTumblebugReady) {
log.info("Checking if Tumblebug is ready");
String apiUrl = createApiUrl("/tumblebug/readyz");
HttpHeaders headers = createCommonHeaders();
try {
ResponseEntity<String> response = restClient.request(apiUrl, headers, null, HttpMethod.GET, new ParameterizedTypeReference<String>() {});
isTumblebugReady = response.getStatusCode().is2xxSuccessful();
lastCheckTime = currentTime;
} catch (Exception e) {
log.error("Tumblebug connection failed", e);
isTumblebugReady = false;
}
}
return isTumblebugReady;
}

public <T> T executeWithConnectionCheck(String operationName, Supplier<T> apiCall) {
if (!checkTumblebug()) {
throw new CbtumblebugException("Tumblebug is not ready");
}
return apiCall.get();
}


public String executeMciCommand(String nsId, String mciId, String command, String subGroupId, String vmId) {
log.info("Executing command on MCI: {}, VM: {}", mciId, vmId);
return executeWithConnectionCheck("executeMciCommand", () -> {
try {
String apiUrl = createApiUrl(String.format("/tumblebug/ns/%s/cmd/mci/%s", nsId, mciId));
HttpHeaders headers = createCommonHeaders();

// 요청 본문 생성
Map<String, Object> requestBody = new HashMap<>();
requestBody.put("command", Collections.singletonList(command));

// 쿼리 파라미터 추가
if (subGroupId != null && !subGroupId.isEmpty()) {
apiUrl += "?subGroupId=" + subGroupId;
}
if (vmId != null && !vmId.isEmpty()) {
apiUrl += (apiUrl.contains("?") ? "&" : "?") + "vmId=" + vmId;
}

String jsonBody = new ObjectMapper().writeValueAsString(requestBody);

ResponseEntity<String> response = restClient.request(
apiUrl,
headers,
jsonBody,
HttpMethod.POST,
new ParameterizedTypeReference<String>() {}
);

if (response.getStatusCode().is2xxSuccessful()) {
String responseBody = response.getBody();
log.info("command result: {}", response.getBody());
ObjectMapper mapper = new ObjectMapper();
JsonNode rootNode = mapper.readTree(responseBody);
JsonNode resultsNode = rootNode.path("results");
if (resultsNode.isArray() && resultsNode.size() > 0) {
JsonNode firstResult = resultsNode.get(0);
String stdout = firstResult.path("stdout").path("0").asText();
String stderr = firstResult.path("stderr").path("0").asText();
if (!stderr.isEmpty()) {
log.warn("Command execution produced stderr: {}", stderr);
}
return stdout;
} else {
throw new CbtumblebugException("Unexpected response format");
}
} else {
throw new CbtumblebugException("MCI command execution failed. Status code: " + response.getStatusCodeValue());
}

} catch (JsonProcessingException e) {
log.error("Error serializing request body", e);
throw new CbtumblebugException("Failed to serialize request body: " + e.getMessage());
} catch (RestClientException e) {
log.error("Error executing command on MCI", e);
throw new CbtumblebugException("Failed to execute command on MCI: " + e.getMessage());
}
});
}

public List<NamespaceDto> getAllNamespace() {
log.info("Fetching all namespaces");
return executeWithConnectionCheck("getAllNamespace", () ->{
Expand All @@ -109,15 +205,27 @@ public List<MciDto> getMcisByNamespace(String namespace) {
});
}

// public String getK8sClusterInfo(){
// log.info("Fetching all K8sClusterInfo");
// return executeWithConnectionCheck("getK8sClusterInfo", () ->{
// String apiUrl = createApiUrl("/k8sClusterInfo");
// HttpHeaders headers = createCommonHeaders();
// ResponseEntity<String> response = restClient.request(apiUrl, headers, headers, HttpMethod.GET, new ParameterizedTypeReference<String>() {});
// return response.getBody() != null ? response.getBody() : null;
// });
// }
public MciAccessInfoDto getSSHKeyForMci(String namespace, String mciId) {
log.info("Fetching SSH Key for MCI: {} in namespace: {}", mciId, namespace);
return executeWithConnectionCheck("getSSHKeyForMci", () -> {
String apiUrl = createApiUrl(String.format("/tumblebug/ns/%s/mci/%s", namespace, mciId));
HttpHeaders headers = createCommonHeaders();

UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(apiUrl)
.queryParam("option", "accessinfo")
.queryParam("accessInfoOption", "showSshKey");

ResponseEntity<MciAccessInfoDto> response = restClient.request(
builder.toUriString(),
headers,
null,
HttpMethod.GET,
new ParameterizedTypeReference<MciAccessInfoDto>() {}
);

return response.getBody();
});
}

public List<K8sClusterDto> getAllK8sClusters(String namespace){
log.info("Fetching K8s Clusters by namespace: {}", namespace);
Expand Down Expand Up @@ -179,21 +287,22 @@ public Spec getSpecBySpecId(String nsId, String specId) {
HttpMethod.GET,
new ParameterizedTypeReference<Spec>() {}
);
log.info("Spec : {}" , response.getBody().toString());
return response.getBody();
});
}

public VmDto getVmInfo(String nsId, String mciId, String vmId) {
public VmAccessInfo getVmInfo(String nsId, String mciId, String vmId) {
log.info("Fetching VM info for VM ID: {}", vmId);
return executeWithConnectionCheck("getVmInfo", () -> {
String apiUrl = createApiUrl(String.format("/tumblebug/ns/%s/mci/%s/vm/%s", nsId, mciId, vmId));
HttpHeaders headers = createCommonHeaders();
ResponseEntity<VmDto> response = restClient.request(
ResponseEntity<VmAccessInfo> response = restClient.request(
apiUrl,
headers,
null,
HttpMethod.GET,
new ParameterizedTypeReference<VmDto>() {}
new ParameterizedTypeReference<VmAccessInfo>() {}
);
return response.getBody();
});
Expand Down Expand Up @@ -228,18 +337,5 @@ public K8sSpec lookupSpec(String connectionName, String cspResourceId) {

return response.getBody();
});
// String apiUrl = "http://localhost:1323/tumblebug/lookupSpec";
// String requestBody = String.format("{\"connectionName\": \"%s\", \"cspResourceId\": \"%s\"}", connectionName, cspResourceId);

// HttpHeaders headers = createCommonHeaders();
// ResponseEntity<K8sSpec> response = restClient.request(
// apiUrl,
// headers,
// requestBody,
// HttpMethod.POST,
// new ParameterizedTypeReference<K8sSpec>() {}
// );

// return response.getBody();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import java.util.List;

import kr.co.mcmp.response.ResponseWrapper;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
Expand All @@ -16,8 +16,8 @@
import kr.co.mcmp.ape.cbtumblebug.dto.NamespaceDto;
import kr.co.mcmp.ape.cbtumblebug.dto.Spec;
import kr.co.mcmp.ape.cbtumblebug.service.CbtumblebugService;
import kr.co.mcmp.response.ResponseWrapper;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.RequestParam;


@Tag(name="tumblebug", description = "Tumblebug API queries")
Expand All @@ -30,38 +30,44 @@ public class CbtumblebugController {

@GetMapping("/ns")
@Operation(summary = "Retrieve all namespaces", description = "Fetches all registered namespaces.")
public ResponseWrapper<List<NamespaceDto>> getAllNamespaces() {
return new ResponseWrapper<>(cbtumblebugService.getAllNamespaces()) ;
public ResponseEntity<ResponseWrapper<List<NamespaceDto>>> getAllNamespaces() {
List<NamespaceDto> result = cbtumblebugService.getAllNamespaces();
return ResponseEntity.ok(new ResponseWrapper<>(result));
}

@GetMapping("/ns/{nsId}/mci")
@Operation(summary = "Retrieve MCIS for a specific namespace", description = "Fetches all MCIS belonging to the specified namespace.")
public ResponseWrapper<List<MciDto>> getMicsByNamespace(@Parameter(description = "Namespace ID", required = true)
public ResponseEntity<ResponseWrapper<List<MciDto>>> getMicsByNamespace(@Parameter(description = "Namespace ID", required = true)
@PathVariable String nsId) {
return new ResponseWrapper<>(cbtumblebugService.getMcisByNamespace(nsId));
List<MciDto> result = cbtumblebugService.getMcisByNamespace(nsId);
return ResponseEntity.ok(new ResponseWrapper<>(result));
}

@GetMapping("/ns/{nsId}/mci/{mciId}")
@Operation(summary = "Retrieve a specific MCI", description = "Fetches the specified MCI.")
public ResponseWrapper<MciDto> getMicByMciId(@PathVariable String nsId, @PathVariable String mciId) {
return new ResponseWrapper<>(cbtumblebugService.getMciByMciId(nsId, mciId));
public ResponseEntity<ResponseWrapper<MciDto>> getMicByMciId(@PathVariable String nsId, @PathVariable String mciId) {
MciDto result = cbtumblebugService.getMciByMciId(nsId, mciId);
return ResponseEntity.ok(new ResponseWrapper<>(result));
}

@GetMapping("/ns/{nsId}/k8scluster")
@Operation(summary = "Retrieve k8sclusters for a specific namespace", description = "Fetches all k8sclusters belonging to the specified namespace.")
public ResponseWrapper<List<K8sClusterDto>> getK8sCluster(@PathVariable String nsId) {
return new ResponseWrapper<>(cbtumblebugService.getAllK8sClusters(nsId));
public ResponseEntity<ResponseWrapper<List<K8sClusterDto>>> getK8sCluster(@PathVariable String nsId) {
List<K8sClusterDto> result = cbtumblebugService.getAllK8sClusters(nsId);
return ResponseEntity.ok(new ResponseWrapper<>(result));
}

@GetMapping("/ns/{nsId}/k8scluster/{clusterName}")
@Operation(summary = "Retrieve a specific k8scluster", description = "Fetches the specified k8scluster.")
public ResponseWrapper<K8sClusterDto> getK8sClusterByName(@PathVariable String nsId, @PathVariable String clusterName) {
return new ResponseWrapper<>(cbtumblebugService.getK8sClusterByName(nsId, clusterName));
public ResponseEntity<ResponseWrapper<K8sClusterDto>> getK8sClusterByName(@PathVariable String nsId, @PathVariable String clusterName) {
K8sClusterDto result = cbtumblebugService.getK8sClusterByName(nsId, clusterName);
return ResponseEntity.ok(new ResponseWrapper<>(result));
}

@GetMapping("/ns/{nsId}/resources/spec/{specId}")
public ResponseWrapper<Spec> getMethodName(@PathVariable String nsId, @PathVariable String specId) {
return new ResponseWrapper<>(cbtumblebugService.getSpecBySpecId(nsId, specId));
public ResponseEntity<ResponseWrapper<Spec>> getMethodName(@PathVariable String nsId, @PathVariable String specId) {
Spec result = cbtumblebugService.getSpecBySpecId(nsId, specId);
return ResponseEntity.ok(new ResponseWrapper<>(result));
}


Expand Down
Loading