27
27
from lean .constants import COMPUTE_MASTER , COMPUTE_SLAVE , COMPUTE_MESSAGING
28
28
29
29
30
- def get_free_port ():
31
- from socket import socket
32
- for i in range (0 , 3 ):
33
- try :
34
- port = 32787 + i
35
- with socket () as s :
36
- s .bind (('' , port ))
37
- return port
38
- except :
39
- pass
40
- return 0
41
-
42
-
43
- def deploy (ip : str , port : int , token : str , slave : bool , update : bool , no_update : bool ,
30
+ def deploy (target_master_domain : str , self_domain : str , port : int , token : str , slave : bool , update : bool , no_update : bool ,
44
31
image : str , lean_config : dict , extra_docker_config : str , counter : int = 0 ):
45
32
logger = container .logger
46
33
47
34
compute_node_name = f"{ COMPUTE_SLAVE } { counter } " if slave else COMPUTE_MASTER
48
35
logger .info (f"Starting { compute_node_name } ..." )
49
36
compute_directory = Path (f"~/.lean/compute/{ compute_node_name } " ).expanduser ()
50
37
lean_config ["node-name" ] = compute_node_name
38
+
51
39
run_options = container .lean_runner .get_basic_docker_config_without_algo (lean_config , None , True , None , None ,
52
40
None , compute_directory )
41
+ run_options ["environment" ]["AIRLOCK" ] = compute_directory
53
42
run_options ["mounts" ].append (Mount (target = "/QuantConnect/platform-services/airlock" ,
54
43
source = str (compute_directory ), type = "bind" ))
55
44
run_options ["mounts" ].append (Mount (target = "/var/run/docker.sock" , source = "/var/run/docker.sock" ,
@@ -59,17 +48,31 @@ def deploy(ip: str, port: int, token: str, slave: bool, update: bool, no_update:
59
48
type = "bind" , read_only = True ))
60
49
container .lean_runner .parse_extra_docker_config (run_options , loads (extra_docker_config ))
61
50
51
+ if not image :
52
+ image = "quantconnect/platform-services:latest"
53
+
54
+ is_domain = not self_domain .replace ('.' , '' ).isnumeric ()
62
55
if not slave :
63
- run_options ["ports" ]["9696" ] = str (port )
64
- run_options ["ports" ]["9697" ] = str (get_free_port ())
56
+ if not is_domain :
57
+ run_options ["ports" ]["9696" ] = str (port )
58
+ run_options ["ports" ]["9697" ] = str (0 )
65
59
66
60
root_directory = container .lean_config_manager .get_cli_root_directory ()
67
61
run_options ["volumes" ][str (root_directory )] = {"bind" : "/LeanCLIWorkspace" , "mode" : "rw" }
68
62
63
+ if is_domain :
64
+ labels = {}
65
+ for name , value in container .docker_manager .get_image_labels (image ):
66
+ if slave and name == "slave" or not slave and name == "master" :
67
+ for key , label in loads (value ).items ():
68
+ labels [key ] = label .replace ("{{domain}}" , self_domain )
69
+ run_options ["labels" ] = labels
70
+
69
71
run_options ["remove" ] = False
70
72
run_options ["name" ] = compute_node_name
71
73
run_options ["environment" ]["MODE" ] = str ('slave' ) if slave else str ('master' )
72
- run_options ["environment" ]["IP" ] = str (ip )
74
+ run_options ["environment" ]["MASTER_DOMAIN" ] = str (target_master_domain )
75
+ run_options ["environment" ]["SELF_DOMAIN" ] = str (self_domain )
73
76
run_options ["environment" ]["PORT" ] = str (port )
74
77
run_options ["environment" ]["TOKEN" ] = str (token )
75
78
run_options ["user" ] = "root"
@@ -103,9 +106,9 @@ def get_ip_address():
103
106
@option ("--master" , is_flag = True , default = False , help = "Run in master mode" )
104
107
@option ("--slave" , is_flag = True , default = False , help = "Run in slave mode" )
105
108
@option ("--token" , type = str , required = False , help = "The master server token" )
106
- @option ("--master-ip " , type = str , required = False , help = "The master server ip address " )
107
- @option ("--master-port" , type = int , required = False , default = 0 , help = "The master server port" )
108
- @option ("--slave-ip " , type = str , required = False , help = "The slave server ip address " )
109
+ @option ("--master-domain " , type = str , required = False , help = "The master server domain " )
110
+ @option ("--master-port" , type = int , required = False , default = 443 , help = "The master server port" )
111
+ @option ("--slave-domain " , type = str , required = False , help = "The slave server domain " )
109
112
@option ("--update" , is_flag = True , default = False , help = "Pull the latest image before starting" )
110
113
@option ("--no-update" , is_flag = True , default = False , help = "Do not update to the latest version" )
111
114
@option ("--compute" , type = str , required = False , help = "Compute configuration to use" )
@@ -115,8 +118,8 @@ def get_ip_address():
115
118
def start (master : bool ,
116
119
slave : bool ,
117
120
token : str ,
118
- master_ip : str ,
119
- slave_ip : str ,
121
+ master_domain : str ,
122
+ slave_domain : str ,
120
123
master_port : int ,
121
124
update : bool ,
122
125
no_update : bool ,
@@ -135,9 +138,9 @@ def start(master: bool,
135
138
# just default to slave if none given
136
139
slave = True
137
140
138
- if not master_ip :
139
- master_ip = get_ip_address ()
140
- logger .info (f"'--master-ip ' was not provided using '{ master_ip } '" )
141
+ if not master_domain :
142
+ master_domain = get_ip_address ()
143
+ logger .info (f"'--master-domain ' was not provided using '{ master_domain } '" )
141
144
142
145
str_mode = 'slave' if slave else 'master'
143
146
logger .info (f'Start running in { str_mode } mode' )
@@ -154,9 +157,7 @@ def start(master: bool,
154
157
155
158
if slave :
156
159
if not token :
157
- raise RuntimeError (f"Master token is required when running as slave" )
158
- if master_port == 0 :
159
- raise RuntimeError (f"Master port is required when running as slave" )
160
+ raise RuntimeError (f"Master token '--token' is required when running as slave" )
160
161
else :
161
162
if not token :
162
163
from uuid import uuid4
@@ -166,41 +167,49 @@ def start(master: bool,
166
167
if any (docker_container ):
167
168
names = [node .name for node in docker_container if node .status == 'running' ]
168
169
if master and (COMPUTE_MASTER in names or COMPUTE_MESSAGING in names ):
169
- raise RuntimeError (f"Private cloud nodes already running detected : { names } " )
170
+ raise RuntimeError (f"Private cloud nodes already running, please use '--stop'. Detected : { names } " )
170
171
logger .info (f"Running nodes: { names } " )
171
172
172
173
container .temp_manager .delete_temporary_directories_when_done = False
173
174
lean_config = container .lean_config_manager .get_complete_lean_config (None , None , None )
174
175
176
+ master_is_domain = not master_domain .replace ('.' , '' ).isnumeric ()
175
177
if master :
176
- deploy (master_ip , master_port , token , False , update , no_update , image , lean_config , extra_docker_config )
178
+ master_port_option = f" --master-port { master_port } "
179
+ if master_is_domain :
180
+ slave_domain = master_domain
181
+ master_port_option = ''
182
+ deploy (master_domain , master_domain , master_port , token , False , update , no_update , image ,
183
+ lean_config , extra_docker_config )
177
184
if master_port == 0 :
178
185
master_port = container .docker_manager .get_container_port (COMPUTE_MASTER , "9696/tcp" )
179
- logger .info (f"Slaves can be added running: "
180
- f"lean private-cloud start --slave --master-ip { master_ip } --token \" { token } \" --master-port { master_port } " )
186
+
187
+ logger .info (f"Slaves can be added running: lean private-cloud start --slave --master-domain { master_domain } "
188
+ f" --slave-domain {{slave.domain}} --token \" { token } \" { master_port_option } " )
181
189
182
190
compute_index = len (get_private_cloud_containers ([COMPUTE_SLAVE ]))
183
191
if compute :
184
192
logger .debug (f"Starting given compute configuration: { compute } " )
185
193
186
- if not slave_ip :
187
- logger .debug (f"'slave-ip ' was not given will try to figure it out..." )
194
+ if not slave_domain :
195
+ logger .debug (f"'slave-domain ' was not given will try to figure it out..." )
188
196
retry_count = 0
189
197
while retry_count < 10 :
190
198
retry_count += 1
191
199
try :
192
200
from requests import get
193
- resp = get (f'http://{ master_ip } :{ master_port } ' , stream = True )
194
- slave_ip = resp .raw ._connection .sock .getsockname ()[0 ]
201
+ resp = get (f'http://{ master_domain } :{ master_port } ' , stream = True )
202
+ slave_domain = resp .raw ._connection .sock .getsockname ()[0 ]
195
203
break
196
204
except Exception as e :
197
205
from time import sleep
198
206
sleep (1 )
199
207
pass
200
- lean_config ["self-ip-address" ] = slave_ip
201
- logger .info (f"Using ip address '{ slave_ip } ' as own" )
208
+ lean_config ["self-ip-address" ] = slave_domain
209
+ logger .debug (f"Using address '{ slave_domain } ' as own" )
202
210
203
211
for configuration in compute :
204
212
lean_config ["compute" ] = configuration
205
213
for i in range (compute_index , int (configuration ["count" ]) + compute_index ):
206
- deploy (master_ip , master_port , token , True , update , no_update , image , lean_config , extra_docker_config , i )
214
+ deploy (master_domain , slave_domain , master_port , token , True , update , no_update , image ,
215
+ lean_config , extra_docker_config , i )
0 commit comments