Skip to content

Commit

Permalink
Merge pull request #64 from JNU-econovation/check_environment
Browse files Browse the repository at this point in the history
[FEAT] Check environment
  • Loading branch information
inferior3x authored Nov 30, 2024
2 parents 3f6b3d0 + 2a2c5ff commit a0c5808
Show file tree
Hide file tree
Showing 11 changed files with 323 additions and 139 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package com.whoz_in.log_writer;


import com.whoz_in.log_writer.common.NetworkInterface;
import com.whoz_in.log_writer.common.process.TransientProcess;
import com.whoz_in.log_writer.config.NetworkConfig;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Component;


@Component
public final class SystemValidator {

public SystemValidator(
@Value("${spring.profiles.active:default}") String profile,
ConfigurableApplicationContext context,
NetworkConfig config
) {
context.getBeanFactory().destroyBean(this);

System.out.println("시스템 검증을 수행합니다..");
String osName = System.getProperty("os.name").toLowerCase();
System.out.println("운영체제: " + osName);
System.out.println("스프링 프로필: " + profile);

if (!profile.equals("prod") || !osName.contains("nux")){
//log-writer는 리눅스에 맞춰서 개발되었으므로 검증도 리눅스 기준으로 수행한다.
//따라서 리눅스가 아니면 개발 환경으로 취급하여 검증을 수행하지 않는다.
System.out.println("리눅스가 아니거나 스프링 프로필이 prod가 아니므로 시스템 검증을 수행하지 않습니다.");
return;
}

checkCommandInstalled("tshark");
checkCommandInstalled("arp-scan");
checkCommandInstalled("iwconfig");

checkNetworkInterfaces(getNetworkInterfaces(), config.getNetworkInterfaces());
System.out.println("시스템 검증 완료");
}

private void checkCommandInstalled(String command) {
List<String> results = new TransientProcess("which " + command).results();
if (results.isEmpty() || !results.get(0).contains("/"))
throw new IllegalStateException(command + "가 설치되지 않았습니다.");
}

//세팅된 NetworkInterface들이 시스템에 존재하는 NetworkInterface인지 확인
private void checkNetworkInterfaces(List<NetworkInterface> system, List<NetworkInterface> setting) {
System.out.println("시스템 네트워크 인터페이스:");
system.forEach(System.out::println);
System.out.println("\n설정된 네트워크 인터페이스:");
setting.forEach(System.out::println);
if (!system.containsAll(setting))
throw new IllegalStateException("로깅하려는 인터페이스가 시스템에 존재하지 않습니다.");
}

private List<NetworkInterface> getNetworkInterfaces() {
List<String> iwconfigOutput = new TransientProcess("iwconfig").results();
List<NetworkInterface> interfaces = new ArrayList<>();

String currentName = null;
String currentEssid = null;
String currentMode = null;

for (String line : iwconfigOutput) {
line = line.trim();
// 인터페이스 이름 감지 (인터페이스 정보 나오기 시작)
if (!line.startsWith(" ") && line.contains("IEEE 802.11")) {
if (currentName != null) {
// 첫 인터페이스가 아니면 모아둔 이전 인터페이스의 정보 저장
interfaces.add(new NetworkInterface(currentName, currentEssid, currentMode));
}
// 새 인터페이스 정보 모으기 & 초기화
currentName = line.split("\\s+")[0];
currentEssid = line.split("ESSID:")[1].split("\\s+")[0].replace("\"", "").trim();
currentMode = null; // 초기화
}
// Mode 추출
if (line.startsWith("Mode:")) {
currentMode = line.split("Mode:")[1].split("\\s")[0].trim().toLowerCase();
}
}

// 마지막 인터페이스 추가
if (currentName != null) {
interfaces.add(new NetworkInterface(currentName, currentEssid, currentMode));
}
return interfaces;
}
}


/*
//샘플 iwconfig
List<String> iwconfigOutput = List.of(
"lo no wireless extensions.",
"",
"eth0 no wireless extensions.",
"",
"default_wlan IEEE 802.11 ESSID:\"JNU\"",
" Mode:Managed Frequency:5.18 GHz Access Point: 50:E4:E0:B9:78:D0",
" Bit Rate=24 Mb/s Tx-Power=31 dBm",
" Retry short limit:7 RTS thr:off Fragment thr:off",
" Power Management:on",
" Link Quality=69/70 Signal level=-41 dBm",
" Rx invalid nwid:0 Rx invalid crypt:0 Rx invalid frag:0",
" Tx excessive retries:12 Invalid misc:0 Missed beacon:0",
"",
"usb_wlan1 IEEE 802.11 ESSID:\"ECONO_5G\"",
" Mode:Managed Frequency:5.745 GHz Access Point: 5A:86:94:45:F0:74",
" Bit Rate=866.7 Mb/s Tx-Power=23 dBm",
" Retry short limit:7 RTS thr:off Fragment thr:off",
" Power Management:on",
" Link Quality=70/70 Signal level=0 dBm",
" Rx invalid nwid:0 Rx invalid crypt:0 Rx invalid frag:0",
" Tx excessive retries:0 Invalid misc:20 Missed beacon:0",
"",
"monitor_wlan IEEE 802.11b ESSID:\"\" Nickname:\"WIFI@RTL8814AU\"",
" Mode:Monitor Frequency:2.462 GHz Access Point: Not-Associated",
" Sensitivity:0/0",
" Retry:off RTS thr:off Fragment thr:off",
" Power Management:off",
" Link Quality:0 Signal level:0 Noise level:0",
" Rx invalid nwid:0 Rx invalid crypt:0 Rx invalid frag:0",
" Tx excessive retries:0 Invalid misc:0 Missed beacon:0"
);
*/
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.whoz_in.log_writer.common;

import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@RequiredArgsConstructor
public final class NetworkInterface{
@EqualsAndHashCode.Include
private final String name;
@EqualsAndHashCode.Include
private final String essid;
@EqualsAndHashCode.Include
private final String mode;

@Override
public String toString() {
return "name: " + name +", ssid: "+ essid + ", mode: "+ mode;
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,59 @@
package com.whoz_in.log_writer.common.process;

import com.whoz_in.log_writer.common.util.NonBlockingBufferedReader;
import jakarta.annotation.Nullable;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
import lombok.NoArgsConstructor;

//실행 후 종료되지 않는 프로세스
//꾸준히 출력을 읽을 수 있어야 한다.
public abstract class ContinuousProcess {
public class ContinuousProcess {
protected Process process;
protected NonBlockingBufferedReader br;

public ContinuousProcess() {}

public ContinuousProcess(Process process) {
this.process = process;
this.br = new NonBlockingBufferedReader(new BufferedReader(new InputStreamReader(process.getInputStream())));
}
public ContinuousProcess(String command) {
this(command, null);
}
public ContinuousProcess(String command, @Nullable String sudoPassword) {
try {
this.process = new ProcessBuilder(command.split(" "))
.redirectErrorStream(true)
.start();
this.br = new NonBlockingBufferedReader(new BufferedReader(new InputStreamReader(this.process.getInputStream())));
if (sudoPassword==null) return;
Writer writer = new OutputStreamWriter(this.process.getOutputStream());
writer.write(sudoPassword + System.lineSeparator());
writer.flush();
} catch (IOException e) {
throw new RuntimeException(command + " 실행 실패");
}
}

//출력이 없을 땐 블로킹되면 안된다.
public abstract String readLine();
public abstract boolean isAlive();
public abstract void terminate();
/**
* @return 프로세스의 출력에서 한 줄을 읽어들인다.
* 읽을 줄이 없을경우 null을 출력한다.
*/
public String readLine(){
try {
return this.br.readLine();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public boolean isAlive(){
return this.process.isAlive();
}
public void terminate(){
this.process.destroy();
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,61 @@
package com.whoz_in.log_writer.common.process;

import jakarta.annotation.Nullable;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import lombok.NoArgsConstructor;

//실행 후 종료되어 모든 출력을 얻는 프로세스
//출력 스트림을 통한 프로세스와의 상호작용은 없다.
public abstract class TransientProcess {
public class TransientProcess {
protected BufferedReader br;
protected Process process;

public TransientProcess() {}

public TransientProcess(Process process){
this.process = process;
this.br = new BufferedReader(new InputStreamReader(process.getInputStream()));
}
public TransientProcess(String command){
this(command, null);
}
public TransientProcess(String command, @Nullable String sudoPassword) {
try {
this.process = new ProcessBuilder(command.split(" "))
.redirectErrorStream(true)
.start();
this.br = new BufferedReader(new InputStreamReader(process.getInputStream()));
if (sudoPassword==null) return;
Writer writer = new OutputStreamWriter(this.process.getOutputStream());
writer.write(sudoPassword + System.lineSeparator());
writer.flush();
} catch (IOException e) {
throw new RuntimeException(e);
}
}

//종료되었을 때 출력을 얻는다.
//종료되지 않았다면 블로킹된다.
public abstract List<String> results();
//출력이 없는 프로세스의 경우 빈 리스트를 출력한다.
public List<String> results(){
List<String> logs = new ArrayList<>();

try {
String line;
while((line = br.readLine()) != null){
logs.add(line);
}
} catch (IOException e) {
throw new RuntimeException(e);
}

return logs;
}
}
Loading

0 comments on commit a0c5808

Please sign in to comment.