@@ -10,6 +10,7 @@ local fio = require('fio')
10
10
local fun = require (' fun' )
11
11
local http_client = require (' http.client' )
12
12
local json = require (' json' )
13
+ local yaml = require (' yaml' )
13
14
local net_box = require (' net.box' )
14
15
local tarantool = require (' tarantool' )
15
16
local uri = require (' uri' )
@@ -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 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.
96
104
-- @tab[opt] extra Table with extra properties for the server object.
97
105
-- @return table
98
106
function Server :new (object , extra )
@@ -127,8 +135,115 @@ function Server:new(object, extra)
127
135
return object
128
136
end
129
137
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
+
130
205
-- Initialize the server object.
131
206
function 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
+
132
247
if self .alias == nil then
133
248
self .alias = DEFAULT_ALIAS
134
249
end
297
412
function Server :start (opts )
298
413
checks (' table' , {wait_until_ready = ' ?boolean' })
299
414
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
+
300
420
self :initialize ()
301
421
302
422
self :make_workdir ()
@@ -550,6 +670,18 @@ function Server:connect_net_box()
550
670
error (connection .error )
551
671
end
552
672
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
553
685
end
554
686
555
687
local function is_header_set (headers , name )
0 commit comments