Skip to content
This repository was archived by the owner on Jan 1, 2024. It is now read-only.

Commit b1f7eef

Browse files
authored
Manage more dynamic box.cfg params (#125)
1 parent dc70dae commit b1f7eef

File tree

11 files changed

+506
-180
lines changed

11 files changed

+506
-180
lines changed

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,19 @@ Environment=TARANTOOL_PID_FILE=/var/run/tarantool/${app_name}.{instance_name}.pi
324324
Environment=TARANTOOL_CONSOLE_SOCK=/var/run/tarantool/${app_name}.{instance_name}.control
325325
```
326326

327+
#### Managing dymanic `box.cfg` parameters without restart
328+
329+
Some `box.cfg` options are dynamic, it means that it can be changed without
330+
instance restarting.
331+
See [parameters](https://www.tarantool.io/en/doc/latest/reference/configuration/#configuration-parameters)
332+
with "Dynamic: yes".
333+
334+
Role changes this parameters without restarting the instance.
335+
If other parameters are changed, instance is restarted anyway.
336+
337+
**Note**, that if `restarted` flag is set, instance will be restarted anyway without changing dynamic parameters in runtime.
338+
You can use this flag to force instance restarting.
339+
327340
#### Increasing memtx_memory in runtime
328341

329342
If you specified in `config.memtx_memory` value that increases current `memtx_memory`, this role will try to increase this value in runtime.

library/cartridge_instance.py

Lines changed: 123 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from ansible.module_utils.basic import AnsibleModule
44
from ansible.module_utils.helpers import ModuleRes, CartridgeException, cartridge_errcodes
55
from ansible.module_utils.helpers import get_control_console
6+
from ansible.module_utils.helpers import dynamic_box_cfg_params, memory_size_box_cfg_params
67

78
import os
89

@@ -14,21 +15,119 @@
1415
}
1516

1617

18+
def serialize_dict(d):
19+
parts = []
20+
21+
for k, v in d.items():
22+
value_str = None
23+
if type(v) == str:
24+
value_str = "'%s'" % v
25+
elif type(v) == float or type(v) == int:
26+
value_str = "%s" % v
27+
elif type(v) == bool:
28+
value_str = 'true' if v else 'false'
29+
else:
30+
raise CartridgeException(
31+
cartridge_errcodes.BAD_VALUE_TYPE,
32+
"Unknown value type: {}" % type(v)
33+
)
34+
35+
parts.append("%s = %s" % (k, value_str))
36+
37+
return '{ %s }' % ', '.join(parts)
38+
39+
40+
def box_cfg_was_called(control_console):
41+
return control_console.eval('''
42+
return type(box.cfg) ~= 'function'
43+
''')
44+
45+
46+
def get_box_cfg(control_console):
47+
return control_console.eval('''
48+
return type(box.cfg) == 'table' and box.cfg or box.NULL
49+
''')
50+
51+
52+
def is_dynamic_param(param_name):
53+
return param_name in dynamic_box_cfg_params
54+
55+
56+
def is_memory_size_param(param_name):
57+
return param_name in memory_size_box_cfg_params
58+
59+
60+
def change_memory_size(param_name, cartridge_defaults, config, control_console):
61+
new_memory_size = config.get(param_name, cartridge_defaults.get(param_name))
62+
63+
if new_memory_size is None:
64+
return False
65+
66+
# Get current memory size
67+
current_memory_size = control_console.eval('''
68+
return type(box.cfg) ~= 'function' and box.cfg.{} or box.NULL
69+
'''.format(param_name))
70+
71+
if current_memory_size is None:
72+
# box.cfg wasn't called
73+
return False
74+
75+
if new_memory_size <= current_memory_size:
76+
return False
77+
78+
# try to increase memory size
79+
increased = control_console.eval('''
80+
local ok, err = pcall(function()
81+
box.cfg {{ {param_name} = {new_memory_size} }}
82+
end)
83+
if not ok then
84+
if tostring(err):find("cannot decrease memory size at runtime") == nil then
85+
error('failed to set {param_name}: ' .. tostring(err))
86+
end
87+
end
88+
return ok
89+
'''.format(param_name=param_name, new_memory_size=new_memory_size))
90+
91+
return increased
92+
93+
94+
def change_dynamic_params(cartridge_defaults, config, control_console):
95+
params = dict()
96+
97+
# Get current values
98+
current_box_cfg = get_box_cfg(control_console)
99+
if current_box_cfg is None:
100+
return False
101+
102+
for param_name, param_value in config.items():
103+
if is_dynamic_param(param_name) and not is_memory_size_param(param_name):
104+
params.update({param_name: param_value})
105+
106+
for param_name, param_value in cartridge_defaults.items():
107+
if param_name in params:
108+
continue
109+
if is_dynamic_param(param_name) and not is_memory_size_param(param_name):
110+
params.update({param_name: param_value})
111+
112+
if not params:
113+
return False
114+
115+
serialized_params = serialize_dict(params)
116+
117+
new_box_cfg = control_console.eval('''
118+
box.cfg({serialized_params})
119+
return box.cfg
120+
'''.format(serialized_params=serialized_params))
121+
122+
changed = new_box_cfg != current_box_cfg
123+
return changed
124+
125+
17126
def manage_instance(params):
18127
config = params['config']
19128
cartridge_defaults = params['cartridge_defaults']
20129
control_sock = params['control_sock']
21130

22-
# Check if memtx_memory parameter is specified
23-
if 'memtx_memory' not in config and 'memtx_memory' not in cartridge_defaults:
24-
return ModuleRes(success=True, changed=False)
25-
26-
new_memtx_memory = None
27-
if 'memtx_memory' in config:
28-
new_memtx_memory = config['memtx_memory']
29-
else:
30-
new_memtx_memory = cartridge_defaults['memtx_memory']
31-
32131
# Check if instance isn't started yet
33132
if not os.path.exists(control_sock):
34133
return ModuleRes(success=True, changed=False)
@@ -46,31 +145,24 @@ def manage_instance(params):
46145

47146
raise e
48147

49-
# Get current memtx memory
50-
current_memtx_memory = control_console.eval('''
51-
return type(box.cfg) ~= 'function' and box.cfg.memtx_memory or box.NULL
52-
''')
53-
if current_memtx_memory is None:
54-
# box.cfg wasn't called
148+
if not box_cfg_was_called(control_console):
55149
return ModuleRes(success=True, changed=False)
56150

57-
if new_memtx_memory <= current_memtx_memory:
58-
return ModuleRes(success=True, changed=False)
151+
# Change memory size
152+
memory_size_changed = False
59153

60-
# try to increase memtx_memory
61-
increased = control_console.eval('''
62-
local ok, err = pcall(function()
63-
box.cfg {{ memtx_memory = {} }}
64-
end)
65-
if not ok then
66-
if tostring(err):find("cannot decrease memory size at runtime") == nil then
67-
error('failed to set memtx_memory: ' .. tostring(err))
68-
end
69-
end
70-
return ok
71-
'''.format(new_memtx_memory))
154+
for param_name in memory_size_box_cfg_params:
155+
if param_name in config or param_name in cartridge_defaults:
156+
memory_size_changed = memory_size_changed or change_memory_size(
157+
param_name, cartridge_defaults, config, control_console
158+
)
159+
160+
# Change dynamic params
161+
dynamic_params_changed = change_dynamic_params(cartridge_defaults, config, control_console)
162+
163+
changed = memory_size_changed or dynamic_params_changed
72164

73-
return ModuleRes(success=True, changed=increased)
165+
return ModuleRes(success=True, changed=changed)
74166

75167

76168
def main():

library/cartridge_needs_restart.py

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from ansible.module_utils.basic import AnsibleModule
44
from ansible.module_utils.helpers import ModuleRes, CartridgeException, cartridge_errcodes
55
from ansible.module_utils.helpers import get_control_console
6+
from ansible.module_utils.helpers import dynamic_box_cfg_params
67

78
import os
89

@@ -70,9 +71,9 @@ def check_conf_updated(new_conf, old_conf, ignore_keys=[]):
7071
return False
7172

7273

73-
def get_memtx_memory(control_console):
74+
def get_current_cfg(control_console):
7475
return control_console.eval('''
75-
return type(box.cfg) ~= 'function' and box.cfg.memtx_memory or box.NULL
76+
return type(box.cfg) ~= 'function' and box.cfg or box.NULL
7677
''')
7778

7879

@@ -125,7 +126,7 @@ def needs_restart(params):
125126
control_console,
126127
conf_section_name
127128
)
128-
if check_conf_updated(new_instance_conf, current_instance_conf, ['memtx_memory']):
129+
if check_conf_updated(new_instance_conf, current_instance_conf, dynamic_box_cfg_params):
129130
return ModuleRes(success=True, changed=True)
130131

131132
if not stateboard:
@@ -136,22 +137,24 @@ def needs_restart(params):
136137
appname
137138
)
138139
new_default_conf.update({'cluster_cookie': cluster_cookie})
139-
if check_conf_updated(new_default_conf, current_default_conf, ['memtx_memory']):
140+
if check_conf_updated(new_default_conf, current_default_conf, dynamic_box_cfg_params):
140141
return ModuleRes(success=True, changed=True)
141142

142-
new_memtx_memory = None
143-
if 'memtx_memory' in new_instance_conf:
144-
new_memtx_memory = new_instance_conf['memtx_memory']
145-
elif not stateboard and 'memtx_memory' in new_default_conf:
146-
new_memtx_memory = new_default_conf['memtx_memory']
147-
148-
# This code is ran after attempt to change memtx_memory in runtime
149-
# If current memtx_memory wasn't changed to the new value,
150-
# it mean that instance should be restarted to apply change
151-
if new_memtx_memory is not None:
152-
current_memtx_memory = get_memtx_memory(control_console)
153-
if current_memtx_memory != new_memtx_memory:
154-
return ModuleRes(success=True, changed=True)
143+
current_cfg = get_current_cfg(control_console)
144+
145+
for param_name in dynamic_box_cfg_params:
146+
new_value = None
147+
if param_name in new_instance_conf:
148+
new_value = new_instance_conf[param_name]
149+
elif not stateboard and param_name in new_default_conf:
150+
new_value = new_default_conf[param_name]
151+
152+
# This code is ran after attempt to change parameter in runtime
153+
# If current parameter wasn't changed to the new value,
154+
# it mean that instance should be restarted to apply change
155+
if new_value is not None:
156+
if current_cfg[param_name] != new_value:
157+
return ModuleRes(success=True, changed=True)
155158

156159
return ModuleRes(success=True, changed=False)
157160

module_utils/helpers.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,52 @@ def __init__(self):
2323
self.BROKEN_PIPE = 'BROKEN_PIPE'
2424
self.FUNCTION_ERROR = 'FUNCTION_ERROR'
2525
self.MISSED_SECTION = 'MISSED_SECTION'
26+
self.BAD_VALUE_TYPE = 'BAD_VALUE_TYPE'
2627

2728

2829
cartridge_errcodes = CartridgeErrorCodes()
2930

3031

32+
# parameters of instance configuration that can be changed dynamically
33+
dynamic_box_cfg_params = set([
34+
'memtx_memory',
35+
'vinyl_memory',
36+
'custom_proc_title',
37+
'listen',
38+
'read_only',
39+
'sql_cache_size',
40+
'vinyl_timeout',
41+
'worker_pool_threads',
42+
'vinyl_cache',
43+
'checkpoint_interval',
44+
'checkpoint_count',
45+
'checkpoint_wal_threshold',
46+
'snap_io_rate_limit',
47+
'replication_connect_timeout',
48+
'replication_connect_quorum',
49+
'replication_skip_conflict',
50+
'replication_sync_lag',
51+
'replication_sync_timeout',
52+
'replication_timeout',
53+
'replication_synchro_quorum',
54+
'replication_synchro_timeout',
55+
'io_collect_interval',
56+
'net_msg_max',
57+
'readahead',
58+
'log_level',
59+
'too_long_threshold',
60+
'log_format',
61+
'feedback_enabled',
62+
'feedback_host',
63+
'feedback_interval',
64+
])
65+
66+
memory_size_box_cfg_params = set([
67+
'memtx_memory',
68+
'vinyl_memory',
69+
])
70+
71+
3172
class CartridgeException(Exception):
3273
def __init__(self, code, message):
3374
super(CartridgeException, self).__init__(message)

tasks/start_instance.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@
55
config: '{{ config }}'
66
cartridge_defaults: '{{ cartridge_defaults }}'
77
when: >-
8-
not restarted and not expelled and
9-
(config.memtx_memory is defined or cartridge_defaults.memtx_memory is defined )
8+
not restarted and not expelled
109
tags: cartridge-instances
1110

1211
- name: Check if instance restart is forced or required to apply changes

unit/helpers.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,5 @@ def add_replicaset(instance, alias, roles, servers,
3131
return replicaset
3232

3333

34-
def set_box_cfg(instace, memtx_memory):
35-
instace.set_box_cfd({
36-
'memtx_memory': memtx_memory,
37-
})
34+
def set_box_cfg(instance, **kwargs):
35+
instance.set_box_cfg(kwargs)

unit/instance.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ def set_variable(self, name, value):
226226
encoded_value=json.dumps(value)
227227
))
228228

229-
def set_box_cfd(self, new_box_cfg):
229+
def set_box_cfg(self, new_box_cfg):
230230
self.eval('''
231231
local value = require('json').decode('{encoded_value}')
232232
require('cartridge').internal.set_box_cfg(value)

0 commit comments

Comments
 (0)