|
25 | 25 | -- * :sync() Sync the configuration and collect a new set of |
26 | 26 | -- instances |
27 | 27 | -- * :reload() Reload the configuration. |
| 28 | +-- * :config() Return the last applied configuration. |
| 29 | +-- * :modify_config() Initialize a configuration builder based on |
| 30 | +-- the current config and store it inside the cluster object. |
| 31 | +-- * :apply_config_changes() Apply the configuration built via |
| 32 | +-- :modify_config() by passing it to :sync(). |
28 | 33 | -- |
29 | 34 | -- The module can also be used for testing failure startup |
30 | 35 | -- cases: |
|
36 | 41 | local fun = require('fun') |
37 | 42 | local yaml = require('yaml') |
38 | 43 | local assertions = require('luatest.assertions') |
| 44 | +local cbuilder = require('luatest.cbuilder') |
39 | 45 | local helpers = require('luatest.helpers') |
40 | 46 | local hooks = require('luatest.hooks') |
41 | 47 | local treegen = require('luatest.treegen') |
@@ -148,6 +154,13 @@ local function instance_names_from_config(config) |
148 | 154 | return instance_names |
149 | 155 | end |
150 | 156 |
|
| 157 | + |
| 158 | +local function assert_no_pending_config_builder(self, method_name) |
| 159 | + assert(self._config_builder == nil, |
| 160 | + (':modify_config() was called; apply configuration changes with ' .. |
| 161 | + ':apply_config_changes() before calling :%s'):format(method_name)) |
| 162 | +end |
| 163 | + |
151 | 164 | -- }}} Helpers |
152 | 165 |
|
153 | 166 | -- {{{ Cluster management |
@@ -226,12 +239,14 @@ end |
226 | 239 | -- @bool[opt] opts.wait_until_running Wait until servers are running |
227 | 240 | -- (default: wait_until_ready; used only if start_stop is set). |
228 | 241 | function Cluster:sync(config, opts) |
| 242 | + assert_no_pending_config_builder(self, 'sync()') |
229 | 243 | assert(type(config) == 'table') |
230 | 244 |
|
231 | 245 | local instance_names = instance_names_from_config(config) |
232 | 246 |
|
233 | 247 | treegen.write_file(self._dir, self._config_file_rel, yaml.encode(config)) |
234 | 248 |
|
| 249 | + self._config = config |
235 | 250 | local server_map = self._server_map |
236 | 251 | self._server_map = {} |
237 | 252 | self._servers = {} |
@@ -277,10 +292,34 @@ function Cluster:sync(config, opts) |
277 | 292 | end |
278 | 293 | end |
279 | 294 |
|
| 295 | +--- Apply configuration changes built via :modify_config(). |
| 296 | +-- |
| 297 | +-- Uses the internal configuration builder created by :modify_config(), |
| 298 | +-- converts it to a config table and calls :sync() with it. |
| 299 | +-- After the call the stored builder is cleared. |
| 300 | +-- |
| 301 | +-- @tab[opt] opts Options. |
| 302 | +-- @bool[opt] opts.start_stop Start/stop added/removed servers |
| 303 | +-- (default: false). |
| 304 | +-- @bool[opt] opts.wait_until_ready Wait until servers are ready |
| 305 | +-- (default: true; used only if start_stop is set). |
| 306 | +-- @bool[opt] opts.wait_until_running Wait until servers are running |
| 307 | +-- (default: wait_until_ready; used only if start_stop is set). |
| 308 | +function Cluster:apply_config_changes(opts) |
| 309 | + assert(self._config_builder ~= nil, |
| 310 | + ':modify_config() must be called before :apply_config_changes()') |
| 311 | + |
| 312 | + local config = self._config_builder:config() |
| 313 | + self._config_builder = nil |
| 314 | + |
| 315 | + return self:sync(config, opts) |
| 316 | +end |
| 317 | + |
280 | 318 | --- Reload configuration on all the instances. |
281 | 319 | -- |
282 | 320 | -- @tab[opt] config New config. |
283 | 321 | function Cluster:reload(config) |
| 322 | + assert_no_pending_config_builder(self, 'reload()') |
284 | 323 | assert(config == nil or type(config) == 'table') |
285 | 324 |
|
286 | 325 | -- Rewrite the configuration file if a new config is provided. |
@@ -333,12 +372,15 @@ function Cluster:new(config, server_opts, opts) |
333 | 372 | assert(g._cluster == nil) |
334 | 373 | end |
335 | 374 |
|
| 375 | + self._config = table.deepcopy(config) |
| 376 | + self._config_builder = nil |
| 377 | + |
336 | 378 | -- Prepare a temporary directory and write a configuration |
337 | 379 | -- file. |
338 | 380 | local dir = opts.dir or treegen.prepare_directory({}, {}) |
339 | 381 | local config_file_rel = 'config.yaml' |
340 | 382 | local config_file = treegen.write_file(dir, config_file_rel, |
341 | | - yaml.encode(config)) |
| 383 | + yaml.encode(self._config)) |
342 | 384 |
|
343 | 385 | -- Collect names of all the instances defined in the config |
344 | 386 | -- in the alphabetical order. |
@@ -383,6 +425,26 @@ function Cluster:new(config, server_opts, opts) |
383 | 425 | return object |
384 | 426 | end |
385 | 427 |
|
| 428 | +--- Return the last applied configuration. |
| 429 | +function Cluster:config() |
| 430 | + assert_no_pending_config_builder(self, 'config()') |
| 431 | + |
| 432 | + return table.deepcopy(self._config) |
| 433 | +end |
| 434 | + |
| 435 | +--- Initialize a configuration builder based on the current config. |
| 436 | +-- |
| 437 | +-- The returned builder is stored inside the cluster object and later |
| 438 | +-- consumed by :apply_config_changes(), which turns it into a config |
| 439 | +-- table and passes it to :sync(). |
| 440 | +function Cluster:modify_config() |
| 441 | + assert(self._config_builder == nil, |
| 442 | + ':modify_config() already called and changes were not applied') |
| 443 | + |
| 444 | + self._config_builder = cbuilder:new(self:config()) |
| 445 | + return self._config_builder |
| 446 | +end |
| 447 | + |
386 | 448 | -- }}} Replicaset management |
387 | 449 |
|
388 | 450 | -- {{{ Replicaset that can't start |
|
0 commit comments