package com.bsmlab.dfx.agent; import com.bsmlab.dfx.agent.config.AgentConfigDto; import com.bsmlab.dfx.agent.config.AgentConfigReader; import com.bsmlab.dfx.agent.config.datasource.DynamicRoutingDataSource; import com.bsmlab.dfx.agent.listener.dto.AckDto; import com.bsmlab.dfx.agent.listener.dto.CommandDto; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.stereotype.Component; import org.springframework.web.client.ResourceAccessException; import org.springframework.web.client.RestTemplate; import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; @Slf4j @RequiredArgsConstructor @Component public class DfxAgentRunner implements ApplicationRunner { private final AgentConfigReader agentConfigReader; private final DynamicRoutingDataSource dynamicRoutingDataSource; @Override public void run(ApplicationArguments args) throws Exception { // command line 실행 중 --check-config 가 있는 경우 settings.json 을 로드하여 DB 연결, knownAgent 연결 테스트를 진행한다. // java -jar $AGENT_HOME/lib/dfxagent.jar --setting.check --setting.file=$AGENT_HOME/conf/settings.json & if(args.containsOption("setting.check")) { this.print("-----------------------"); this.print("DfxAgent 설정 및 환경 점검"); this.print("-----------------------"); this.print(" (설정 파일: " + args.getOptionValues("setting.file") + ")"); // settings.json 점검 로직 boolean isValid = true; this.print(""); this.print("데이터베이스 설정 점검"); Map dataSourceMap = dynamicRoutingDataSource.getDataSourceMap(); if(dataSourceMap != null && !dataSourceMap.isEmpty()) { for(Object key : dataSourceMap.keySet()) { DataSource dataSource = (DataSource) dataSourceMap.get(key); AgentConfigDto.DataSourceConfig dataSourceConfig = null; List dataSourceConfigList = agentConfigReader.getAgentConfigDto().getDataSourceConfig(); for(AgentConfigDto.DataSourceConfig thisDataSourceConfig : dataSourceConfigList) { if(thisDataSourceConfig.getDataSourceId().equals(key)) { dataSourceConfig = thisDataSourceConfig; break; } } this.print("DB 점검 [" + dataSourceConfig.toString() + "]"); try(Connection connection = dataSource.getConnection()) { connection.isValid(10); this.print("DB 연결에 성공하였습니다."); } catch(SQLException e) { this.print("DB 연결에 실패하였습니다. (" + e.getLocalizedMessage() + ")"); isValid = false; } catch(Exception e) { this.print("DB 점검에 실패하였습니다. (" + e.getLocalizedMessage() + ")"); isValid = false; } } } else { this.print("데이터베이스 설정은 포함되어 있지 않습니다."); isValid = false; } this.print(""); this.print("상대 agent 설정 점검"); List knownAgentList = agentConfigReader.getAgentConfigDto().getKnownAgentList(); if(knownAgentList != null && !knownAgentList.isEmpty()) { Map knownAgentMap = new HashMap<>(); for(AgentConfigDto.KnownAgent knownAgent : knownAgentList) { knownAgentMap.put(knownAgent.getHostId(), knownAgent); try { String messageUuid = UUID.randomUUID().toString(); CommandDto commandDto = CommandDto.builder().commandType(CommandDto.CommandType.ALIVE).messageUuid(messageUuid).build(); HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.setContentType(MediaType.APPLICATION_JSON); httpHeaders.set("User-Agent", agentConfigReader.getApplicationName() + ", version: " + agentConfigReader.getApplicationVersion() + "(" + agentConfigReader.getApplicationCommitId() + ")" + ", host ID: " + agentConfigReader.getAgentConfigDto().getMyHostId()); HttpEntity bodyEntity = new HttpEntity<>(commandDto, httpHeaders); RestTemplate restTemplate = new RestTemplate(); String url = "http://" + knownAgent.getHostName() + ":" + knownAgent.getListenPort() + "/command"; this.print("상대 agent " + knownAgent.getHostId() + "(" + knownAgent.getHostName() + ":" + knownAgent.getListenPort() + ") 연결 점검"); String response = restTemplate.postForObject(url, bodyEntity, String.class); ObjectMapper objectMapper = new ObjectMapper(); AckDto ackDto = null; ackDto = objectMapper.readValue(response, new TypeReference() {}); if(AckDto.ResultType.PROCESS_SUCCESS == ackDto.getResult()) { this.print("상대 agent " + knownAgent.getHostId() + "(" + knownAgent.getHostName() + "가 정상 동작합니다."); commandDto.setCommandType(CommandDto.CommandType.INFORMATION); bodyEntity = new HttpEntity<>(commandDto, httpHeaders); this.print("상대 agent " + knownAgent.getHostId() + "(" + knownAgent.getHostName() + ":" + knownAgent.getListenPort() + ") DropBox 점검"); response = restTemplate.postForObject(url, bodyEntity, String.class); ackDto = objectMapper.readValue(response, new TypeReference() {}); AgentConfigDto knownAgentConfigDto = objectMapper.readValue(ackDto.getResultText(), new TypeReference() {}); List knownAgentDropBoxList = knownAgentConfigDto.getDropBoxConfig().getDropBoxList(); if(knownAgent.getDropBoxIdList() != null) { if(knownAgentDropBoxList != null) { for(String dropBoxId : knownAgent.getDropBoxIdList()) { boolean isHasDropBoxId = false; for(AgentConfigDto.DropBox knwonAgentDropBox : knownAgentDropBoxList) { if(dropBoxId.equals(knwonAgentDropBox.getDropBoxId())) { isHasDropBoxId = true; } } if(!isHasDropBoxId) { this.print("DropBoxId " + dropBoxId + "에 해당하는 상대 agent " + knownAgent.getHostId() + "(" + knownAgent.getHostName() + ")의 DropBoxId가 존재하지 않습니다."); isValid = false; } } } else { this.print("상대 agent " + knownAgent.getHostId() + "(" + knownAgent.getHostName() + ")의 DropBox 설정이 존재하지 않습니다."); isValid = false; } } } else { this.print("상대 agent " + knownAgent.getHostId() + "(" + knownAgent.getHostName() + ")가 응답하였으나 정상 동작하지 않습니다."); isValid = false; } } catch (JsonProcessingException e) { this.print("상대 agent " + knownAgent.getHostId() + "(" + knownAgent.getHostName() + ")가 응답메시지가 정상적이지 않습니다. (" + e.getLocalizedMessage() + ")"); isValid = false; } catch (ResourceAccessException e) { this.print("상대 agent " + knownAgent.getHostId() + "(" + knownAgent.getHostName() + ")가 응답하지 않습니다. (" + e.getLocalizedMessage() + ")"); isValid = false; } catch (Exception e) { this.print("상대 agent " + knownAgent.getHostId() + "(" + knownAgent.getHostName() + ") 상태를 알 수 없습니다. (" + e.getLocalizedMessage() + ")"); isValid = false; } } this.print(""); this.print("Postman 설정 점검"); if(agentConfigReader.getAgentConfigDto().getPostmanConfig() != null) { this.print("Postman thread pool size: " + agentConfigReader.getAgentConfigDto().getPostmanConfig().getThreadPoolSize()); List postManList = agentConfigReader.getAgentConfigDto().getPostmanConfig().getPostmanList(); if(postManList != null) { for(AgentConfigDto.Postman postman : postManList) { AgentConfigDto.KnownAgent knownAgent = knownAgentMap.get(postman.getRecipientHostId()); if(knownAgent != null) { boolean isHasDropBoxId = false; for(String knownAgentDropBoxId : knownAgent.getDropBoxIdList()) { if(postman.getRecipientDropBoxId().equals(knownAgentDropBoxId)) { isHasDropBoxId = true; } } if(!isHasDropBoxId) { this.print("postman " + postman.getPostmanId() + "에 대한 recipientDropBoxId(" + postman.getRecipientDropBoxId() + ")가 knownAgent(" + knownAgent.getHostId() + ") dropBoxIdList 목록에 존재하지 않습니다."); isValid = false; } } else { this.print("postman " + postman.getPostmanId() + "에 대한 recipientHostId(" + postman.getRecipientHostId() + ")가 knownAgent 목록에 존재하지 않습니다."); isValid = false; } } } else { this.print("Postman 목록 없음"); } } else { this.print("Postman 설정 없음"); isValid = false; } } else { this.print("상대 agent 설정은 포함되어 있지 않습니다."); isValid = false; } this.print(""); this.print("--------------------------------------"); if(isValid) { this.print("설정과 환경이 정상적입니다."); this.print("점검을 종료합니다."); System.exit(0); } else { this.print("설정 또는 환경에 오류가 포함되어 있습니다."); this.print("점검을 종료합니다."); System.exit(2); } this.print("--------------------------------------"); } } private void print(String text) { System.out.println(text); } }