trove backup
introduction
backup
api:create_backup —-> taskmanager:create_backup —-> self.guest.create_backup —-> rabbitmq —-> guestagent:mysql_manager:create_backup —-> innobackupex —-> swift put
taskmanager 中的 create_backup
trove/taskmanager/manager.py
1
2
3
4class Manager(periodic_task.PeriodicTasks):
def create_backup(self, context, backup_info, instance_id):
instance_tasks = models.BuiltInstanceTasks.load(context, instance_id)
instance_tasks.create_backup(backup_info)
trove/taskmanager/models.py
1
2
3
4class BuiltInstanceTasks(BuiltInstance, NotifyMixin, ConfigurationMixin):
def create_backup(self, backup_info):
LOG.info(_(“Initiating backup for instance %s.”) % self.id)
self.guest.create_backup(backup_info)
这里的 self.guest trove/instance/models.py
1
2
3class BaseInstance(SimpleInstance):
def get_guest(self):
return create_guest_client(self.context, self.db_info.id)
trove/common/remote.py
1
2
3
4
5
6
7
8
9create_guest_client = import_class(CONF.remote_guest_client)
def guest_client(context, id, manager=None):
from trove.guestagent.api import API
if manager:
clazz = strategy.load_guestagent_strategy(manager).guest_client_class
else:
clazz = API
return clazz(context, id)
所以 guest 对应的是 API 实例, cast()发送消息。guestagent 接受到消息
guestagent 中的 createbackup
trove/guestagent/datastore/mysql/manager.py
1
2
3class Manager(periodic_task.PeriodicTasks):
def create_backup(self, context, backup_info):
backup.backup(context, backup_info)
trove/guestagent/backup/backupagent.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71# innobackupex 或 mysqldump
RUNNER = get_backup_strategy(STRATEGY, BACKUP_NAMESPACE)
# 额外的参数,如使用 innobackupex,可以有–user os_admin –socket /var/lib/mysql/mysql.sock
EXTRA_OPTS = CONF.backup_runner_options.get(STRATEGY, ‘’)
class BackupAgent(object):
def stream_backup_to_storage(self, backup_info, runner, storage,
parent_metadata={}, extra_opts=EXTRA_OPTS):
backup_id = backup_info[‘id’]
ctxt = trove_context.TroveContext(
user=CONF.nova_proxy_admin_user,
auth_token=CONF.nova_proxy_admin_pass)
conductor = conductor_api.API(ctxt)
# Store the size of the filesystem before the backup.
mount_point = CONFIG_MANAGER.mount_point
stats = get_filesystem_volume_stats(mount_point)
backup_state = {
‘backup_id’: backup_id,
‘size’: stats.get(‘used’, 0.0),
‘state’: BackupState.BUILDING,
}
conductor.update_backup(CONF.guest_id,
sent=timeutils.float_utcnow(),
backup_state)
LOG.debug(“Updated state for %s to %s.”, backup_id, backup_state)
with runner(filename=backup_id, extra_opts=extra_opts,
parent_metadata) as bkup:
try:
LOG.debug(“Starting backup %s.”, backup_id)
success, note, checksum, location = storage.save(
bkup.manifest,
bkup)
backup_state.update({
‘checksum’: checksum,
‘location’: location,
‘note’: note,
‘success’: success,
‘backup_type’: bkup.backup_type,
})
. . .
if not success:
raise BackupError(note)
meta = bkup.metadata()
meta[‘datastore’] = backup_info[‘datastore’]
meta[‘datastore_version’] = backup_info[
‘datastore_version’]
storage.save_metadata(location, meta)
backup_state.update({‘state’: BackupState.COMPLETED})
return meta
. . .
def execute_backup(self, context, backup_info,
runner=RUNNER, extra_opts=EXTRA_OPTS):
LOG.debug(“Running backup %(id)s.”, backup_info)
storage = get_storage_strategy(
CONF.storage_strategy,
CONF.storage_namespace)(context)
#是否是 incremental backup
. . .
self.stream_backup_to_storage(backup_info, runner, storage,
parent_metadata, extra_opts)
RUNNER 对应的是 trove.guestagent.strategies.backup.mysql_impl:InnoBackupEx/InnoBackupExIncremental
, 使用 stream backup
1
2
3
4
5
6
7class BackupRunner(Strategy):
def enter(self):
“””Start up the process.”””
self._run_pre_backup()
self.run()
return self
storage 对应的是 trove.guestagent.strategies.storage.swift:SwiftStorage
, 从 stream read 出来 使用 swift put 上传.
radosgw’s swift api
rgw 集成 keystone 部分配置
1 | rgw keystone url = http://192.168.6.125:5000 |
rgw 接受到 swift 请求之后处理
1 | ret = handler->authorize(); |
请求携带 token,对 token 进行验证
1
bool RGWSwift::verify_swift_token(RGWRados store, req_state s)
validatetoken 返回详细信息和其 tenant、user、role 等信息, 对应请求的 keystone API /v2.0/tokens/{tokenId}
1
validate_keystone_token(store, s->os_auth_token, &info, s->user);
1
parse_keystone_token_response(token, bl, info, t)
parse 之后的 info
1
{status = 200, auth_groups = “”, user = “a400d920a63642d4913e8f2f3afda408”, display_name = “demo”, ttl = 0}
1
update_user_info(store, info, rgw_user);
对应关系:
1
2info user –> keystone tenant_id –> rgw uid
info display_name –> keystone tenant_name –> rgw display_name
那使用 rgw swift 来作 trove backup, 但是很遗憾。trove 配置项 backup_swift_container = database_backups
, 创建 backup 时为 tenant 创建一个 container 用来存放 backup,但是 rgw 的 bucket_name 是全局的,swift 中 containername 是 tenant 下的。当我使用第二个 tenant 去创建 backups 时,会先创建database<sub>backups</sub>
的 bucket,而这个 bucket 已被占用,BuceketAlreadyExist
或许可以使用 database_backups_$(tenant_id) 的 bucket 来存储,这种方式在 juno 版是可以(trove juno 使 swift DLO 方式上传)trove master 使用了 swift SLO 的方式,目前 rgw swift 不支持。so, openstack or implement s3 in trove.