156
|
1 import typing
|
|
2 import subprocess
|
|
3 import time
|
|
4
|
|
5 from DbType import DbType
|
|
6
|
|
7 class DbServer:
|
|
8
|
|
9 class DockerDefinition:
|
|
10
|
|
11 def __init__(self, image: str, internalPort: int, envVars: typing.Dict[str, str], storagePath: str, command: typing.List[str]=None):
|
|
12 self.image = image
|
|
13 self.internalPort = internalPort
|
|
14 self.envVars = envVars
|
|
15 self.storagePath = storagePath
|
|
16 self.command = command
|
|
17
|
|
18 def __init__(self, dbType: DbType, port: int):
|
|
19
|
|
20 self.port = port
|
|
21 self.dbType = dbType
|
|
22
|
|
23 self._containerId = None
|
|
24 self._label = None
|
|
25
|
|
26 def setLabel(self, label: str):
|
|
27 self._label = label
|
|
28
|
|
29 def launch(self):
|
|
30 dockerDefinition = self.getDockerDefinition()
|
|
31
|
|
32 # check if the container is already running
|
|
33 ret = subprocess.call([
|
|
34 "docker",
|
|
35 "top",
|
|
36 self._label
|
|
37 ])
|
|
38 if ret == 0:
|
|
39 print("DbServer is already running")
|
|
40 return
|
|
41
|
|
42 # create a volume (if it already exists, it wont be modified)
|
|
43 subprocess.check_call([
|
|
44 "docker",
|
|
45 "volume",
|
|
46 "create",
|
|
47 "--name=" + self._label
|
|
48 ])
|
|
49
|
|
50 dockerRunCommand = [
|
|
51 "docker",
|
|
52 "run",
|
|
53 "-d",
|
|
54 "--name=" + self._label,
|
|
55 "-p", str(self.port) + ":" + str(dockerDefinition.internalPort),
|
|
56 "--volume=" + self._label + ":" + dockerDefinition.storagePath
|
|
57 ]
|
|
58
|
|
59 if len(dockerDefinition.envVars) > 0:
|
|
60 for k,v in dockerDefinition.envVars.items():
|
|
61 dockerRunCommand.extend(["--env", k + "=" + v])
|
|
62
|
|
63 dockerRunCommand.append(
|
|
64 dockerDefinition.image
|
|
65 )
|
|
66
|
|
67 if dockerDefinition.command is not None:
|
|
68 dockerRunCommand.extend(
|
|
69 dockerDefinition.command
|
|
70 )
|
|
71
|
|
72 print("Launching DbServer")
|
|
73 subprocess.check_call(dockerRunCommand)
|
|
74
|
|
75 print("Waiting for DbServer to be ready")
|
|
76
|
|
77 # wait until its port is open
|
|
78 retryCounter = 0
|
|
79 connected = False
|
|
80 while not connected and retryCounter < 30:
|
|
81 time.sleep(1)
|
|
82 connected = subprocess.call(["nc", "-z", "localhost", str(self.port)]) == 0
|
|
83 if retryCounter >= 30:
|
|
84 print("DbServer still not ready after 30 sec")
|
|
85 raise TimeoutError
|
|
86
|
|
87 def stop(self):
|
|
88 subprocess.check_call([
|
|
89 "docker",
|
|
90 "stop",
|
|
91 self._label
|
|
92 ])
|
|
93 subprocess.check_call([
|
|
94 "docker",
|
|
95 "rm",
|
|
96 self._label
|
|
97 ])
|
|
98
|
|
99 def clear(self):
|
|
100 # remove the volume
|
|
101 self.stop()
|
|
102 subprocess.check_call([
|
|
103 "docker",
|
|
104 "volume",
|
|
105 "rm",
|
|
106 self._label
|
|
107 ])
|
|
108
|
|
109
|
|
110 def getDockerDefinition(self):
|
|
111 if self.dbType == DbType.MySQL:
|
|
112 return DbServer.DockerDefinition(
|
|
113 image="mysql:8.0",
|
|
114 internalPort=3306,
|
|
115 envVars={
|
|
116 "MYSQL_PASSWORD": "orthanc",
|
|
117 "MYSQL_USER": "orthanc",
|
|
118 "MYSQL_DATABASE": "orthanc",
|
|
119 "MYSQL_ROOT_PASSWORD": "foo-root"
|
|
120 },
|
|
121 storagePath="/var/lib/mysql",
|
|
122 command=["mysqld", "--default-authentication-plugin=mysql_native_password", "--log-bin-trust-function-creators=1"]
|
|
123 )
|
|
124 elif self.dbType == DbType.MSSQL:
|
|
125 return DbServer.DockerDefinition(
|
|
126 image="microsoft/mssql-server-linux",
|
|
127 internalPort=1433,
|
|
128 envVars={
|
|
129 "ACCEPT_EULA": "Y",
|
|
130 "SA_PASSWORD": "MyStrOngPa55word!"
|
|
131 },
|
|
132 storagePath="/var/opt/mssql/data"
|
|
133 )
|
|
134 elif self.dbType == DbType.PG9 or self.dbType == DbType.PG10:
|
|
135 if self.dbType == DbType.PG9:
|
|
136 image = "postgres:9"
|
|
137 elif self.dbType == DbType.PG10:
|
|
138 image = "postgres:10"
|
|
139 return DbServer.DockerDefinition(
|
|
140 image=image,
|
|
141 internalPort=5432,
|
|
142 envVars={
|
|
143 },
|
|
144 storagePath="/var/lib/postgresql/data"
|
|
145 )
|
|
146
|