1+ #!/usr/bin/env python3
2+
3+ import os
4+ import requests # HTTP ์์ฒญ์ ์ํ ๋ชจ๋ ์ถ๊ฐ
5+ import subprocess
6+ import time
7+ from typing import Dict , Optional
8+
9+
10+ class ServiceManager :
11+ # ์ด๊ธฐํ ํจ์
12+ def __init__ (self , socat_port : int = 8081 , sleep_duration : int = 3 ) -> None :
13+ self .socat_port : int = socat_port
14+ self .sleep_duration : int = sleep_duration
15+ self .services : Dict [str , int ] = {
16+ 'cmf_1' : 8082 ,
17+ 'cmf_2' : 8083
18+ }
19+ self .current_name : Optional [str ] = None
20+ self .current_port : Optional [int ] = None
21+ self .next_name : Optional [str ] = None
22+ self .next_port : Optional [int ] = None
23+
24+ # ํ์ฌ ์คํ ์ค์ธ ์๋น์ค๋ฅผ ์ฐพ๋ ํจ์
25+ def _find_current_service (self ) -> None :
26+ cmd : str = f"ps aux | grep 'socat -t0 TCP-LISTEN:{ self .socat_port } ' | grep -v grep | awk '{{print $NF}}'"
27+ current_service : str = subprocess .getoutput (cmd )
28+ if not current_service :
29+ self .current_name , self .current_port = 'cmf_2' , self .services ['cmf_2' ]
30+ else :
31+ self .current_port = int (current_service .split (':' )[- 1 ])
32+ self .current_name = next ((name for name , port in self .services .items () if port == self .current_port ), None )
33+
34+ # ๋ค์์ ์คํํ ์๋น์ค๋ฅผ ์ฐพ๋ ํจ์
35+ def _find_next_service (self ) -> None :
36+ self .next_name , self .next_port = next (
37+ ((name , port ) for name , port in self .services .items () if name != self .current_name ),
38+ (None , None )
39+ )
40+
41+ # Docker ์ปจํ
์ด๋๋ฅผ ์ ๊ฑฐํ๋ ํจ์
42+ def _remove_container (self , name : str ) -> None :
43+ os .system (f"docker stop { name } 2> /dev/null" )
44+ os .system (f"docker rm -f { name } 2> /dev/null" )
45+
46+ # Docker ์ปจํ
์ด๋๋ฅผ ์คํํ๋ ํจ์
47+ def _run_container (self , name : str , port : int ) -> None :
48+ os .system (
49+ f"docker run -d --name={ name } --restart unless-stopped -p { port } :8090 -e TZ=Asia/Seoul -v /dockerProjects/cmf/volumes/gen:/gen --pull always ghcr.io/commitfield/commitfield" )
50+
51+ def _switch_port (self ) -> None :
52+ # Socat ํฌํธ๋ฅผ ์ ํํ๋ ํจ์
53+ cmd : str = f"ps aux | grep 'socat -t0 TCP-LISTEN:{ self .socat_port } ' | grep -v grep | awk '{{print $2}}'"
54+ pid : str = subprocess .getoutput (cmd )
55+
56+ if pid :
57+ os .system (f"kill -9 { pid } 2>/dev/null" )
58+
59+ time .sleep (5 )
60+
61+ os .system (
62+ f"nohup socat -t0 TCP-LISTEN:{ self .socat_port } ,fork,reuseaddr TCP:localhost:{ self .next_port } &>/dev/null &" )
63+
64+ # ์๋น์ค ์ํ๋ฅผ ํ์ธํ๋ ํจ์
65+
66+ def _is_service_up (self , port : int ) -> bool :
67+ url = f"http://127.0.0.1:{ port } /actuator/health"
68+ try :
69+ response = requests .get (url , timeout = 5 ) # 5์ด ์ด๋ด ์๋ต ์์ผ๋ฉด ์์ธ ๋ฐ์
70+ if response .status_code == 200 and response .json ().get ('status' ) == 'UP' :
71+ return True
72+ except requests .RequestException :
73+ pass
74+ return False
75+
76+ # ์๋น์ค๋ฅผ ์
๋ฐ์ดํธํ๋ ํจ์
77+ def update_service (self ) -> None :
78+ self ._find_current_service ()
79+ self ._find_next_service ()
80+
81+ self ._remove_container (self .next_name )
82+ self ._run_container (self .next_name , self .next_port )
83+
84+ # ์ ์๋น์ค๊ฐ 'UP' ์ํ๊ฐ ๋ ๋๊น์ง ๊ธฐ๋ค๋ฆผ
85+ while not self ._is_service_up (self .next_port ):
86+ print (f"Waiting for { self .next_name } to be 'UP'..." )
87+ time .sleep (self .sleep_duration )
88+
89+ self ._switch_port ()
90+
91+ if self .current_name is not None :
92+ self ._remove_container (self .current_name )
93+
94+ print ("Switched service successfully!" )
95+
96+
97+ if __name__ == "__main__" :
98+ manager = ServiceManager ()
99+ manager .update_service ()
0 commit comments