-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #64 from JNU-econovation/check_environment
[FEAT] Check environment
- Loading branch information
Showing
11 changed files
with
323 additions
and
139 deletions.
There are no files selected for viewing
130 changes: 130 additions & 0 deletions
130
modules/infrastructure/log-writer/src/main/java/com/whoz_in/log_writer/SystemValidator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" | ||
); | ||
*/ |
22 changes: 22 additions & 0 deletions
22
...frastructure/log-writer/src/main/java/com/whoz_in/log_writer/common/NetworkInterface.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} |
58 changes: 53 additions & 5 deletions
58
...ure/log-writer/src/main/java/com/whoz_in/log_writer/common/process/ContinuousProcess.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
} | ||
} |
53 changes: 51 additions & 2 deletions
53
...ture/log-writer/src/main/java/com/whoz_in/log_writer/common/process/TransientProcess.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} |
Oops, something went wrong.