@@ -10,6 +10,7 @@ local fio = require('fio')
1010local fun = require (' fun' )
1111local http_client = require (' http.client' )
1212local json = require (' json' )
13+ local yaml = require (' yaml' )
1314local net_box = require (' net.box' )
1415local tarantool = require (' tarantool' )
1516local uri = require (' uri' )
@@ -39,6 +40,9 @@ local Server = {
3940 args = ' ?table' ,
4041 box_cfg = ' ?table' ,
4142
43+ config_file = ' ?string' ,
44+ remote_config = ' ?table' ,
45+
4246 http_port = ' ?number' ,
4347 net_box_port = ' ?number' ,
4448 net_box_uri = ' ?string|table' ,
9397-- `net.box` connection to the new server.
9498-- @tab[opt] object.box_cfg Extra options for `box.cfg()` and the value of the
9599-- `TARANTOOL_BOX_CFG` env variable which is passed into the server process.
100+ -- @string[opt] object.config_file Declarative YAML configuration for server
101+ -- instance. Used to deduce advertise URI to connect net.box to the instance.
102+ -- @tab[opt] object.remote_config If `config_file` is not passed, this config
103+ -- value is used to deduce the advertise URI to connect net.box to the instance.
96104-- @tab[opt] extra Table with extra properties for the server object.
97105-- @return table
98106function Server :new (object , extra )
@@ -127,8 +135,115 @@ function Server:new(object, extra)
127135 return object
128136end
129137
138+ -- Determine advertise URI for given instance from a cluster
139+ -- configuration.
140+ local function find_advertise_uri (config , instance_name , dir )
141+ local urilib = require (' uri' )
142+ if config == nil or next (config ) == nil then
143+ return nil
144+ end
145+
146+ -- Determine listen and advertise options that are in effect
147+ -- for the given instance.
148+ local advertise
149+ local listen
150+
151+ for _ , group in pairs (config .groups or {}) do
152+ for _ , replicaset in pairs (group .replicasets or {}) do
153+ local instance = (replicaset .instances or {})[instance_name ]
154+ if instance == nil then
155+ break
156+ end
157+ if instance .iproto ~= nil then
158+ if instance .iproto .advertise ~= nil then
159+ advertise = advertise or instance .iproto .advertise .client
160+ end
161+ listen = listen or instance .iproto .listen
162+ end
163+ if replicaset .iproto ~= nil then
164+ if replicaset .iproto .advertise ~= nil then
165+ advertise = advertise or replicaset .iproto .advertise .client
166+ end
167+ listen = listen or replicaset .iproto .listen
168+ end
169+ if group .iproto ~= nil then
170+ if group .iproto .advertise ~= nil then
171+ advertise = advertise or group .iproto .advertise .client
172+ end
173+ listen = listen or group .iproto .listen
174+ end
175+ end
176+ end
177+
178+ if config .iproto ~= nil then
179+ if config .iproto .advertise ~= nil then
180+ advertise = advertise or config .iproto .advertise .client
181+ end
182+ listen = listen or config .iproto .listen
183+ end
184+
185+ local uris
186+ if advertise ~= nil then
187+ uris = {{uri = advertise }}
188+ else
189+ uris = listen
190+ end
191+ -- luacheck: push ignore 431
192+ for _ , uri in ipairs (uris or {}) do
193+ uri = table .copy (uri )
194+ uri .uri = uri .uri :gsub (' {{ *instance_name *}}' , instance_name )
195+ uri .uri = uri .uri :gsub (' unix/:%./' , (' unix/:%s/' ):format (dir ))
196+ local u = urilib .parse (uri )
197+ if u .ipv4 ~= ' 0.0.0.0' and u .ipv6 ~= ' ::' and u .service ~= ' 0' then
198+ return uri
199+ end
200+ end
201+ -- luacheck: pop
202+ error (' No suitable URI to connect is found' )
203+ end
204+
130205-- Initialize the server object.
131206function Server :initialize ()
207+ if self .config_file ~= nil then
208+ self .command = arg [- 1 ]
209+
210+ self .args = fun .chain (self .args or {}, {
211+ ' --name' , self .alias
212+ }):totable ()
213+
214+ if self .config_file ~= ' ' then
215+ table.insert (self .args , ' --config' )
216+ table.insert (self .args , self .config_file )
217+
218+ -- Take into account self.chdir to calculate a config
219+ -- file path.
220+ local config_file_path = utils .pathjoin (self .chdir , self .config_file )
221+
222+ -- Read the provided config file.
223+ local fh , err = fio .open (config_file_path , {' O_RDONLY' })
224+ if fh == nil then
225+ error ((' Unable to open file %q: %s' ):format (config_file_path ,
226+ err ))
227+ end
228+ self .config = yaml .decode (fh :read ())
229+ fh :close ()
230+ end
231+
232+ if self .net_box_uri == nil then
233+ local config = self .config or self .remote_config
234+
235+ -- NB: listen and advertise URIs are relative to
236+ -- process.work_dir, which, in turn, is relative to
237+ -- self.chdir.
238+ local work_dir
239+ if config .process ~= nil and config .process .work_dir ~= nil then
240+ work_dir = config .process .work_dir
241+ end
242+ local dir = utils .pathjoin (self .chdir , work_dir )
243+ self .net_box_uri = find_advertise_uri (config , self .alias , dir )
244+ end
245+ end
246+
132247 if self .alias == nil then
133248 self .alias = DEFAULT_ALIAS
134249 end
297412function Server :start (opts )
298413 checks (' table' , {wait_until_ready = ' ?boolean' })
299414
415+ opts = opts or {}
416+ if self .config_file and opts .wait_until_ready == nil then
417+ opts .wait_until_ready = self .net_box_uri ~= nil
418+ end
419+
300420 self :initialize ()
301421
302422 self :make_workdir ()
@@ -550,6 +670,18 @@ function Server:connect_net_box()
550670 error (connection .error )
551671 end
552672 self .net_box = connection
673+
674+ if self .config_file ~= nil then
675+ -- Replace the ready condition.
676+ local saved_eval = self .net_box .eval
677+ self .net_box .eval = function (self , expr , args , opts ) -- luacheck:ignore 432
678+ if expr == ' return _G.ready' then
679+ expr = " return require('config'):info().status == 'ready' or " ..
680+ " require('config'):info().status == 'check_warnings'"
681+ end
682+ return saved_eval (self , expr , args , opts )
683+ end
684+ end
553685end
554686
555687local function is_header_set (headers , name )
0 commit comments