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