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

Commit 431ce0e

Browse files
authored
Add step to backup stopped instances (#409)
Closes #405 Now it's possible to backup stopped instance by `backup_instance_dirs` step. This makes it possible to transfer instances from one host to another. Also, now it's possible to restore instances from local backup by `restore` step with `cartridge_restore_backup_path_local` variable.
1 parent faaa513 commit 431ce0e

21 files changed

+487
-13
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ Please update `ansible-galaxy install` command in
1010
README.md to use the newest tag with new release
1111
-->
1212

13+
### Added
14+
15+
- Add `backup_instance_dirs` step to archive files of stopped instance
16+
- Add `cartridge_restore_backup_path_local` to restore instance from local backup
17+
1318
### Fixed
1419

1520
- Remove old app configurations before uploading a new one

defaults/main.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ cartridge_remote_backups_dir: /opt/tarantool/backups
163163
cartridge_fetch_backups: false
164164
cartridge_fetch_backups_dir: backups/
165165
cartridge_restore_backup_path: null
166+
cartridge_restore_backup_path_local: null
166167
cartridge_force_restore: false
167168
cartridge_allow_alien_backup: false
168169
cartridge_skip_cleanup_on_restore: false
@@ -313,6 +314,7 @@ cartridge_cached_fact_names_by_target:
313314
- cartridge_fetch_backups
314315
- cartridge_fetch_backups_dir
315316
- cartridge_restore_backup_path
317+
- cartridge_restore_backup_path_local
316318
- cartridge_force_restore
317319
- cartridge_allow_alien_backup
318320
- cartridge_skip_cleanup_on_restore

doc/steps.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ but can be used in a custom one:
4343
- [backup](#step-backup)
4444
- [backup_start](#step-backup_start)
4545
- [backup_stop](#step-backup_stop)
46+
- [backup_instance_dirs](#step-backup_instance_dirs)
4647
- [restore](#step-restore)
4748
- [check_new_topology](#step-check_new_topology)
4849

@@ -591,11 +592,32 @@ Input variables from config:
591592
(`.tarantool.cookie` will be kept independently of this variable);
592593
it's possible to use bash patterns, e.g. `*.control`.
593594
- `cartridge_restore_backup_path` - path to the instance backup archive on the remote machine;
595+
- `cartridge_restore_backup_path_local` - path to the instance backup archive on the local machine;
594596
- `cartridge_remote_backups_dir` - directory with backups on the remote;
595597
- `cartridge_force_restore` - flag indicates that conflicting files should be overwritten;
596598
- `cartridge_allow_alien_backup` - flag indicates that backup of instance with another name can be used;
597599
- `cartridge_skip_cleanup_on_restore` - flag indicates that cleanup before restoring should be skipped.
598600

601+
### Step `backup_instance_dirs`
602+
603+
Create a [backup](/doc/backups.md) archive for each **stopped** instance and fetch it on the local machine.
604+
605+
Input variables from config:
606+
607+
- `cartridge_remote_backups_dir` - directory to store backups on the remote;
608+
- `cartridge_fetch_backups` - flag indicates that backups should be fetched the local machine;
609+
- `cartridge_fetch_backups_dir` - a directory on the local machine where backups should be fetched if `cartridge_fetch_backups` is `true`. This path is relative to the playbook path;
610+
- `cartridge_app_user` - user which will own the links;
611+
- `cartridge_app_group` - group which will own the links;
612+
- `stateboard` - indicates that the instance is a stateboard.
613+
614+
Output facts:
615+
616+
- `instance_backup_files` - list of instance files to back up;
617+
- `backup_files_from_machine` - list of files to back up for all instances on the same machine as a current one;
618+
- `backup_archive_path` - path to the instance backup archive on the remote machine;
619+
- `fetched_backup_archive_path` - path to the fetched backup file (is set only if `cartridge_fetch_backups` is `true`).
620+
599621
## Step `check_new_topology`
600622

601623
Check for dangerous changes on edit topology

doc/variables.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,8 @@ For more details see [scenario documentation](/doc/scenario.md).
212212
the playbook path.
213213
- `cartridge_restore_backup_path` (`string`): path to the instance backup archive on the remote
214214
machine;
215+
- `cartridge_restore_backup_path_local` (`string`): path to the instance backup archive on the local
216+
machine;
215217
- `cartridge_force_restore` (`boolean`, default: `false`): flag indicates that conflicting files
216218
should be overwritten;
217219
- `cartridge_allow_alien_backup` (`boolean`, default: `false`): flag indicates that backup of

library/cartridge_backup_instance.py

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,25 @@
55
from ansible.module_utils.helpers import Helpers as helpers
66

77
argument_spec = {
8-
'console_sock': {'required': True, 'type': 'str'},
8+
'console_sock': {'required': False, 'type': 'str'},
99
'instance_id': {'required': False, 'type': 'str'},
1010
'stateboard': {'required': False, 'type': 'bool'},
1111
'backups_dir': {'required': False, 'type': 'str'},
1212
'instance_conf_file': {'required': False, 'type': 'str'},
1313
'app_conf_file': {'required': False, 'type': 'str'},
14-
1514
'start_only': {'required': False, 'type': 'bool', 'default': False},
1615
'stop_only': {'required': False, 'type': 'bool', 'default': False},
16+
'custom_backup_files': {'required': False, 'type': 'list'},
1717
}
1818

1919

2020
def backup_start(control_console, params):
21-
stateboard = params['stateboard']
22-
instance_conf_file = params['instance_conf_file']
23-
app_conf_file = params['app_conf_file']
21+
stateboard = params.get('stateboard')
22+
assert stateboard is not None, 'Parameter "stateboard" is required'
23+
instance_conf_file = params.get('instance_conf_file')
24+
assert instance_conf_file is not None, 'Parameter "instance_conf_file" is required'
25+
app_conf_file = params.get('app_conf_file')
26+
assert app_conf_file is not None, 'Parameter "app_conf_file" is required'
2427

2528
# create snapshot and start a backup
2629
backup_files, err = control_console.eval_res_err('''
@@ -81,7 +84,8 @@ def backup_pack(instance_id, backups_dir, backup_files):
8184

8285
with tarfile.open(archive_path, "w:gz") as tar:
8386
for path in backup_files:
84-
tar.add(path)
87+
if os.path.exists(path):
88+
tar.add(path)
8589

8690
return archive_path
8791

@@ -97,13 +101,27 @@ def backup_stop(control_console):
97101
return None
98102

99103

100-
def call_backup(params):
101-
start_only = params['start_only']
102-
stop_only = params['stop_only']
104+
def custom_backup(params):
105+
custom_backup_files = helpers.get_required_param(params, 'custom_backup_files')
106+
107+
# ARCHIVE
108+
instance_id = helpers.get_required_param(params, 'instance_id')
109+
backups_dir = helpers.get_required_param(params, 'backups_dir')
110+
backup_archive_path = backup_pack(instance_id, backups_dir, custom_backup_files)
111+
112+
return helpers.ModuleRes(changed=True, fact={
113+
'backup_archive_path': backup_archive_path,
114+
'backup_files': custom_backup_files,
115+
})
116+
117+
118+
def tnt_backup(params):
119+
start_only = params.get('start_only', False)
120+
stop_only = params.get('stop_only', False)
103121

104122
assert not (start_only and stop_only), "impossible to use 'start_only' with 'stop_only'"
105123

106-
console_sock = params['console_sock']
124+
console_sock = helpers.get_required_param(params, 'console_sock')
107125
control_console = helpers.get_control_console(console_sock)
108126

109127
if not helpers.box_cfg_was_called(control_console):
@@ -128,8 +146,8 @@ def call_backup(params):
128146
})
129147

130148
# ARCHIVE
131-
instance_id = params['instance_id']
132-
backups_dir = params['backups_dir']
149+
instance_id = helpers.get_required_param(params, 'instance_id')
150+
backups_dir = helpers.get_required_param(params, 'backups_dir')
133151
backup_archive_path = backup_pack(instance_id, backups_dir, backup_files)
134152

135153
# STOP
@@ -143,5 +161,12 @@ def call_backup(params):
143161
})
144162

145163

164+
def call_backup(params):
165+
if params.get('custom_backup_files'):
166+
return custom_backup(params)
167+
else:
168+
return tnt_backup(params)
169+
170+
146171
if __name__ == '__main__':
147172
helpers.execute_module(argument_spec, call_backup)

library/cartridge_get_instance_info.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ def get_instance_systemd_service(app_name, instance_name, stateboard=False):
3131
return '%s@%s' % (app_name, instance_name)
3232

3333

34+
def get_instance_systemd_service_template(app_name, stateboard=False):
35+
if stateboard:
36+
return '%s-stateboard.service' % app_name
37+
return '%[email protected]' % app_name
38+
39+
3440
def get_instance_systemd_service_dir(systemd_dir, service_name):
3541
if not service_name.endswith('.service'):
3642
service_name += '.service'
@@ -74,18 +80,21 @@ def get_instance_info(params):
7480
'paths_to_remove_on_expel': set(),
7581
'files_to_remove_on_cleanup': set(),
7682
'dirs_to_remove_on_cleanup': set(),
83+
'paths_to_backup_files': set(),
7784
}
7885

7986
# app conf file
8087
instance_info['app_conf_file'] = get_app_conf_file(
8188
instance_vars['cartridge_conf_dir'], app_name
8289
)
90+
instance_info['paths_to_backup_files'].add(instance_info['app_conf_file'])
8391

8492
# instance conf file
8593
instance_info['conf_file'] = get_instance_conf_file(
8694
instance_vars['cartridge_conf_dir'], app_name, instance_name, instance_vars['stateboard'],
8795
)
8896
instance_info['paths_to_remove_on_expel'].add(instance_info['conf_file'])
97+
instance_info['paths_to_backup_files'].add(instance_info['conf_file'])
8998

9099
# instance id (e.g. used for conf section name)
91100
instance_info['instance_id'] = get_instance_conf_section(
@@ -111,6 +120,7 @@ def get_instance_info(params):
111120
)
112121
instance_info['paths_to_remove_on_expel'].add(instance_info['work_dir'])
113122
instance_info['dirs_to_remove_on_cleanup'].add(instance_info['work_dir'])
123+
instance_info['paths_to_backup_files'].add(instance_info['work_dir'])
114124

115125
# instance memtx dir
116126
instance_info['memtx_dir'] = None
@@ -120,6 +130,7 @@ def get_instance_info(params):
120130
)
121131
instance_info['paths_to_remove_on_expel'].add(instance_info['memtx_dir'])
122132
instance_info['dirs_to_remove_on_cleanup'].add(instance_info['memtx_dir'])
133+
instance_info['paths_to_backup_files'].add(instance_info['memtx_dir'])
123134

124135
# instance vinyl dir
125136
instance_info['vinyl_dir'] = None
@@ -129,6 +140,7 @@ def get_instance_info(params):
129140
)
130141
instance_info['paths_to_remove_on_expel'].add(instance_info['vinyl_dir'])
131142
instance_info['dirs_to_remove_on_cleanup'].add(instance_info['vinyl_dir'])
143+
instance_info['paths_to_backup_files'].add(instance_info['vinyl_dir'])
132144

133145
# instance wal dir
134146
instance_info['wal_dir'] = None
@@ -138,6 +150,7 @@ def get_instance_info(params):
138150
)
139151
instance_info['paths_to_remove_on_expel'].add(instance_info['wal_dir'])
140152
instance_info['dirs_to_remove_on_cleanup'].add(instance_info['wal_dir'])
153+
instance_info['paths_to_backup_files'].add(instance_info['wal_dir'])
141154

142155
# instance log dir
143156
instance_info['log_file'] = None
@@ -153,16 +166,22 @@ def get_instance_info(params):
153166
instance_info['systemd_service'] = get_instance_systemd_service(
154167
app_name, instance_name, instance_vars['stateboard']
155168
)
169+
instance_info['paths_to_backup_files'].add(get_instance_systemd_service_template(
170+
app_name, instance_vars['stateboard']
171+
))
172+
156173
instance_info['systemd_service_dir'] = get_instance_systemd_service_dir(
157174
instance_vars['cartridge_systemd_dir'],
158175
instance_info['systemd_service'],
159176
)
160177
instance_info['systemd_service_env_file'] = get_systemd_service_env_file(instance_info['systemd_service_dir'])
178+
instance_info['paths_to_backup_files'].add(instance_info['systemd_service_env_file'])
161179

162180
# tmpfiles conf
163181
instance_info['tmpfiles_conf'] = os.path.join(
164182
instance_vars['cartridge_tmpfiles_dir'], '%s.conf' % app_name
165183
)
184+
instance_info['paths_to_backup_files'].add(instance_info['tmpfiles_conf'])
166185

167186
# code dirs
168187
if not instance_vars['cartridge_multiversion']:
@@ -182,6 +201,7 @@ def get_instance_info(params):
182201
)
183202

184203
instance_info['paths_to_remove_on_expel'] = list(sorted(instance_info['paths_to_remove_on_expel']))
204+
instance_info['paths_to_backup_files'] = list(sorted(instance_info['paths_to_backup_files']))
185205

186206
instance_info['files_to_remove_on_cleanup'] = list(sorted(filter_paths_by_glob_list(
187207
instance_info['files_to_remove_on_cleanup'],

library/cartridge_validate_config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@
182182
'cartridge_fetch_backups': bool,
183183
'cartridge_fetch_backups_dir': str,
184184
'cartridge_restore_backup_path': str,
185+
'cartridge_restore_backup_path_local': str,
185186
'cartridge_force_restore': bool,
186187
'cartridge_allow_alien_backup': bool,
187188
'cartridge_skip_cleanup_on_restore': bool,

module_utils/helpers.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -723,6 +723,11 @@ def glob_list_match(path, glob_list):
723723
return False
724724

725725

726+
def get_required_param(params, name):
727+
assert params.get(name) is not None, 'Parameter "%s" is required' % name
728+
return params[name]
729+
730+
726731
class Helpers:
727732
DYNAMIC_BOX_CFG_PARAMS = DYNAMIC_BOX_CFG_PARAMS
728733
MEMORY_SIZE_BOX_CFG_PARAMS = MEMORY_SIZE_BOX_CFG_PARAMS
@@ -766,3 +771,4 @@ class Helpers:
766771
get_disabled_instances = staticmethod(get_disabled_instances)
767772
get_topology_checksum = staticmethod(get_topology_checksum)
768773
glob_list_match = staticmethod(glob_list_match)
774+
get_required_param = staticmethod(get_required_param)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../common/Dockerfile.j2

0 commit comments

Comments
 (0)