@@ -12,7 +12,8 @@ local http_client = require('http.client')
12
12
local json = require (' json' )
13
13
local net_box = require (' net.box' )
14
14
local tarantool = require (' tarantool' )
15
- local uri = require (' uri' )
15
+ local urilib = require (' uri' )
16
+ local yaml = require (' yaml' )
16
17
local _ , luacov_runner = pcall (require , ' luacov.runner' ) -- luacov may not be installed
17
18
18
19
local assertions = require (' luatest.assertions' )
@@ -39,6 +40,9 @@ local Server = {
39
40
args = ' ?table' ,
40
41
box_cfg = ' ?table' ,
41
42
43
+ config_file = ' ?string' ,
44
+ remote_config = ' ?table' ,
45
+
42
46
http_port = ' ?number' ,
43
47
net_box_port = ' ?number' ,
44
48
net_box_uri = ' ?string|table' ,
93
97
-- `net.box` connection to the new server.
94
98
-- @tab[opt] object.box_cfg Extra options for `box.cfg()` and the value of the
95
99
-- `TARANTOOL_BOX_CFG` env variable which is passed into the server process.
100
+ -- @string[opt] object.config_file Declarative YAML configuration for a server
101
+ -- instance. Used to deduce advertise URI to connect net.box to the instance.
102
+ -- The special value '' means running without `--config <...>` CLI option
103
+ -- (but still passes `--name <alias>`).
104
+ -- @tab[opt] object.remote_config If `config_file` is not passed, this config
105
+ -- value is used to deduce advertise URI to connect net.box to the instance.
96
106
-- @tab[opt] extra Table with extra properties for the server object.
97
107
-- @return table
98
108
function Server :new (object , extra )
@@ -127,8 +137,111 @@ function Server:new(object, extra)
127
137
return object
128
138
end
129
139
140
+ -- Determine advertise URI for given instance from a cluster
141
+ -- configuration.
142
+ local function find_advertise_uri (config , instance_name , dir )
143
+ if config == nil or next (config ) == nil then
144
+ return nil
145
+ end
146
+
147
+ -- Determine listen and advertise options that are in effect
148
+ -- for the given instance.
149
+ local advertise
150
+ local listen
151
+
152
+ for _ , group in pairs (config .groups or {}) do
153
+ for _ , replicaset in pairs (group .replicasets or {}) do
154
+ local instance = (replicaset .instances or {})[instance_name ]
155
+ if instance == nil then
156
+ break
157
+ end
158
+ if instance .iproto ~= nil then
159
+ if instance .iproto .advertise ~= nil then
160
+ advertise = advertise or instance .iproto .advertise .client
161
+ end
162
+ listen = listen or instance .iproto .listen
163
+ end
164
+ if replicaset .iproto ~= nil then
165
+ if replicaset .iproto .advertise ~= nil then
166
+ advertise = advertise or replicaset .iproto .advertise .client
167
+ end
168
+ listen = listen or replicaset .iproto .listen
169
+ end
170
+ if group .iproto ~= nil then
171
+ if group .iproto .advertise ~= nil then
172
+ advertise = advertise or group .iproto .advertise .client
173
+ end
174
+ listen = listen or group .iproto .listen
175
+ end
176
+ end
177
+ end
178
+
179
+ if config .iproto ~= nil then
180
+ if config .iproto .advertise ~= nil then
181
+ advertise = advertise or config .iproto .advertise .client
182
+ end
183
+ listen = listen or config .iproto .listen
184
+ end
185
+
186
+ local uris
187
+ if advertise ~= nil then
188
+ uris = {{uri = advertise }}
189
+ else
190
+ uris = listen
191
+ end
192
+ -- luacheck: push ignore 431
193
+ for _ , uri in ipairs (uris or {}) do
194
+ uri = table .copy (uri )
195
+ uri .uri = uri .uri :gsub (' {{ *instance_name *}}' , instance_name )
196
+ uri .uri = uri .uri :gsub (' unix/:%./' , (' unix/:%s/' ):format (dir ))
197
+ local u = urilib .parse (uri )
198
+ if u .ipv4 ~= ' 0.0.0.0' and u .ipv6 ~= ' ::' and u .service ~= ' 0' then
199
+ return uri
200
+ end
201
+ end
202
+ -- luacheck: pop
203
+ error (' No suitable URI to connect is found' )
204
+ end
205
+
130
206
-- Initialize the server object.
131
207
function Server :initialize ()
208
+ if self .config_file ~= nil then
209
+ self .command = arg [- 1 ]
210
+
211
+ self .args = fun .chain (self .args or {}, {' --name' , self .alias }):totable ()
212
+
213
+ if self .config_file ~= ' ' then
214
+ table.insert (self .args , ' --config' )
215
+ table.insert (self .args , self .config_file )
216
+
217
+ -- Take into account self.chdir to calculate a config
218
+ -- file path.
219
+ local config_file_path = utils .pathjoin (self .chdir , self .config_file )
220
+
221
+ -- Read the provided config file.
222
+ local fh , err = fio .open (config_file_path , {' O_RDONLY' })
223
+ if fh == nil then
224
+ error ((' Unable to open file %q: %s' ):format (config_file_path , err ))
225
+ end
226
+ self .config = yaml .decode (fh :read ())
227
+ fh :close ()
228
+ end
229
+
230
+ if self .net_box_uri == nil then
231
+ local config = self .config or self .remote_config
232
+
233
+ -- NB: listen and advertise URIs are relative to
234
+ -- process.work_dir, which, in turn, is relative to
235
+ -- self.chdir.
236
+ local work_dir
237
+ if config .process ~= nil and config .process .work_dir ~= nil then
238
+ work_dir = config .process .work_dir
239
+ end
240
+ local dir = utils .pathjoin (self .chdir , work_dir )
241
+ self .net_box_uri = find_advertise_uri (config , self .alias , dir )
242
+ end
243
+ end
244
+
132
245
if self .alias == nil then
133
246
self .alias = DEFAULT_ALIAS
134
247
end
@@ -157,7 +270,7 @@ function Server:initialize()
157
270
self .net_box_uri = ' localhost:' .. self .net_box_port
158
271
end
159
272
end
160
- local parsed_net_box_uri = uri .parse (self .net_box_uri )
273
+ local parsed_net_box_uri = urilib .parse (self .net_box_uri )
161
274
if parsed_net_box_uri .host == ' unix/' then
162
275
-- Linux uses max 108 bytes for Unix domain socket paths, which means a 107 characters
163
276
-- string ended by a null terminator. Other systems use 104 bytes and 103 characters strings.
@@ -170,7 +283,7 @@ function Server:initialize()
170
283
end
171
284
end
172
285
if type (self .net_box_uri ) == ' table' then
173
- self .net_box_uri = uri .format (parsed_net_box_uri , true )
286
+ self .net_box_uri = urilib .format (parsed_net_box_uri , true )
174
287
end
175
288
176
289
self .env = utils .merge (self .env or {}, self :build_env ())
281
394
--- Make directory for the server's Unix socket.
282
395
-- Invoked on the server's start.
283
396
function Server :make_socketdir ()
284
- local parsed_net_box_uri = uri .parse (self .net_box_uri )
397
+ local parsed_net_box_uri = urilib .parse (self .net_box_uri )
285
398
if parsed_net_box_uri .host == ' unix/' then
286
399
fio .mktree (fio .dirname (parsed_net_box_uri .service ))
287
400
end
@@ -333,10 +446,14 @@ function Server:start(opts)
333
446
})
334
447
335
448
local wait_until_ready
336
- if self .coverage_report then
337
- wait_until_ready = self .original_command == DEFAULT_INSTANCE
449
+ if self .config_file then
450
+ wait_until_ready = self .net_box_uri ~= nil
338
451
else
339
- wait_until_ready = self .command == DEFAULT_INSTANCE
452
+ if self .coverage_report then
453
+ wait_until_ready = self .original_command == DEFAULT_INSTANCE
454
+ else
455
+ wait_until_ready = self .command == DEFAULT_INSTANCE
456
+ end
340
457
end
341
458
if opts ~= nil and opts .wait_until_ready ~= nil then
342
459
wait_until_ready = opts .wait_until_ready
@@ -499,10 +616,18 @@ end
499
616
--- Wait until the server is ready after the start.
500
617
-- A server is considered ready when its `_G.ready` variable becomes `true`.
501
618
function Server :wait_until_ready ()
619
+ local expr
620
+ if self .config_file ~= nil then
621
+ expr = " return require('config'):info().status == 'ready' or " ..
622
+ " require('config'):info().status == 'check_warnings'"
623
+ else
624
+ expr = ' return _G.ready'
625
+ end
626
+
502
627
wait_for_condition (' server is ready' , self , function ()
503
628
local ok , is_ready = pcall (function ()
504
629
self :connect_net_box ()
505
- return self .net_box :eval (' return _G.ready ' ) == true
630
+ return self .net_box :eval (expr ) == true
506
631
end )
507
632
return ok and is_ready
508
633
end )
0 commit comments