Freezer Backup for nova and cinder should accept instances names

Added parameters ‘nova_inst_name’ and ‘cinder_vol_name’
to take freezer backups for nova and cinder.

Change-Id: Iafe7e50b66fc727b2099b45e4b26f083768ef858
Closes-Bug: #1603099
This commit is contained in:
Vishakha Agarwal 2018-04-09 14:19:23 +05:30 committed by Nguyen Hai
parent 370009349f
commit 5226536301
6 changed files with 164 additions and 22 deletions

View File

@ -930,6 +930,7 @@ Available options::
usage: freezer-agent [-h] [--action ACTION] [--always-level ALWAYS_LEVEL]
[--backup-name BACKUP_NAME]
[--cinder-vol-id CINDER_VOL_ID]
[--cinder-vol-name CINDER_VOL_NAME]
[--cindernative-vol-id CINDERNATIVE_VOL_ID]
[--command COMMAND] [--compression COMPRESSION]
[--config CONFIG] [--config-dir DIR] [--config-file PATH]
@ -955,6 +956,7 @@ Available options::
[--nodry-run] [--noinsecure] [--nooverwrite] [--noquiet]
[--nouse-syslog] [--nouse-syslog-rfc-format]
[--nova-inst-id NOVA_INST_ID] [--noverbose]
[--nova-inst-name NOVA_INST_NAME]
[--nowatch-log-file]
[--os-identity-api-version OS_IDENTITY_API_VERSION]
[--overwrite] [--path-to-backup PATH_TO_BACKUP]
@ -993,6 +995,8 @@ optional arguments:
backup on Swift
--cinder-vol-id CINDER_VOL_ID
Id of cinder volume for backup
--cinder-vol-name CINDER_VOL_NAME
Name of cinder volume for backup
--cindernative-vol-id CINDERNATIVE_VOL_ID
Id of cinder volume for native backup
--command COMMAND Command executed by exec action
@ -1126,6 +1130,8 @@ optional arguments:
The inverse of --use-syslog-rfc-format
--nova-inst-id NOVA_INST_ID
Id of nova instance for backup
--nova-inst-name NOVA_INST_NAME
Name of nova instance for backup
--noverbose The inverse of --verbose
--nowatch-log-file The inverse of --watch-log-file
--os-identity-api-version OS_IDENTITY_API_VERSION, --os_auth_ver OS_IDENTITY_API_VERSION

View File

@ -566,6 +566,14 @@ OPTIONS
Id of cinder volume for backup
.. oslo.config:option:: cinder_vol_name
:Type: string
:Default:
Name of cinder volume for backup
.. oslo.config:option:: cinderbrick_vol_id
:Type: string
@ -598,6 +606,14 @@ OPTIONS
Id of nova instance for backup
.. oslo.config:option:: nova_inst_name
:Type: string
:Default:
Name of nova instance for backup
.. oslo.config:option:: project_id
:Type: string

View File

@ -69,7 +69,9 @@ DEFAULT_PARAMS = {
'encrypt_pass_file': None, 'volume': None, 'proxy': None,
'cinder_vol_id': '', 'cindernative_vol_id': '',
'cinderbrick_vol_id': '',
'cinder_vol_name': '',
'nova_inst_id': '', '__version__': FREEZER_VERSION,
'nova_inst_name': '',
'remove_older_than': None, 'restore_from_date': None,
'upload_limit': -1, 'always_level': False, 'version': None,
'dry_run': False, 'lvm_snapsize': DEFAULT_LVM_SNAPSIZE,
@ -375,6 +377,11 @@ _COMMON = [
default=DEFAULT_PARAMS['cinder_vol_id'],
help="Id of cinder volume for backup"
),
cfg.StrOpt('cinder-vol-name',
dest='cinder_vol_name',
default=DEFAULT_PARAMS['cinder_vol_name'],
help="Name of cinder volume for backup"
),
cfg.StrOpt('cinderbrick-vol-id',
dest='cinderbrick_vol_id',
default=DEFAULT_PARAMS['cinderbrick_vol_id'],
@ -395,6 +402,12 @@ _COMMON = [
default=DEFAULT_PARAMS['nova_inst_id'],
help="Id of nova instance for backup"
),
cfg.StrOpt('nova-inst-name',
dest='nova_inst_name',
default=DEFAULT_PARAMS['nova_inst_name'],
help="Name of nova instance for backup"
),
cfg.StrOpt('project-id',
dest='project_id',
default=DEFAULT_PARAMS['project_id'],
@ -653,12 +666,13 @@ def get_backup_args():
backup_args.path_to_backup[:3]
backup_media = 'fs'
if backup_args.cinder_vol_id:
if backup_args.cinder_vol_id or backup_args.cinder_vol_name:
backup_media = 'cinder'
elif backup_args.cindernative_vol_id or backup_args.cindernative_backup_id:
backup_media = 'cindernative'
elif backup_args.engine_name == 'nova' and (backup_args.project_id or
backup_args.nova_inst_id):
backup_args.nova_inst_id or
backup_args.nova_inst_name):
backup_media = 'nova'
elif backup_args.cinderbrick_vol_id:
backup_media = 'cinderbrick'

View File

@ -15,6 +15,7 @@
import abc
from concurrent import futures
import datetime
import os
import sys
@ -25,6 +26,7 @@ from oslo_log import log
from oslo_utils import importutils
import six
from freezer.common import client_manager
from freezer.openstack import admin
from freezer.openstack import backup
from freezer.openstack import restore
@ -48,8 +50,21 @@ class Job(object):
self.conf = conf_dict
self.storage = storage
self.engine = conf_dict.engine
self.client = client_manager.get_client_manager(CONF)
self.nova = self.client.get_nova()
self.cinder = self.client.get_cinder()
self._general_validation()
self._validate()
if self.conf.nova_inst_name:
self.nova_instance_ids = [server.id for server in
self.nova.servers.list(detailed=False)
if server.name ==
self.conf.nova_inst_name]
if self.conf.cinder_vol_name:
self.cinder_vol_ids = [volume.id for volume in
self.cinder.volumes.list()
if volume.name ==
self.conf.cinder_inst_name]
@abc.abstractmethod
def _validate(self):
@ -124,13 +139,15 @@ class BackupJob(Job):
if not self.conf.no_incremental:
raise ValueError("Incremental nova backup is not supported")
if not self.conf.nova_inst_id and not self.conf.project_id:
raise ValueError("nova-inst-id or project-id"
if not self.conf.nova_inst_id and not self.conf.project_id \
and not self.conf.nova_inst_name:
raise ValueError("nova-inst-id or project-id or nova-inst-name"
" argument must be provided")
if self.conf.mode == 'cinder':
if not self.conf.cinder_vol_id:
raise ValueError("cinder-vol-id argument must be provided")
if not self.conf.cinder_vol_id and not self.conf.cinder_vol_name:
raise ValueError("cinder-vol-id or cinder-vol-name argument "
"must be provided")
if self.conf.mode == "cindernative":
if not self.conf.cindernative_vol_id:
@ -266,9 +283,11 @@ class BackupJob(Job):
max_level=self.conf.max_level,
always_level=self.conf.always_level,
restart_always_level=self.conf.restart_always_level)
else:
elif self.conf.nova_inst_id:
LOG.info('Executing nova backup. Instance ID: {0}'.format(
self.conf.nova_inst_id))
hostname_backup_name = os.path.join(
self.conf.hostname_backup_name,
self.conf.nova_inst_id)
@ -280,6 +299,25 @@ class BackupJob(Job):
always_level=self.conf.always_level,
restart_always_level=self.conf.restart_always_level)
else:
executor = futures.ThreadPoolExecutor(
max_workers=len(self.nova_instance_ids))
futures_list = []
for instance_id in self.nova_instance_ids:
hostname_backup_name = os.path.join(
self.conf.hostname_backup_name, instance_id)
futures_list.append(executor.submit(
self.engine.backup(
backup_resource=instance_id,
hostname_backup_name=hostname_backup_name,
no_incremental=self.conf.no_incremental,
max_level=self.conf.max_level,
always_level=self.conf.always_level,
restart_always_level=self.conf.restart_always_level
)))
futures.wait(futures_list, CONF.timeout)
elif backup_media == 'cindernative':
LOG.info('Executing cinder native backup. Volume ID: {0}, '
'incremental: {1}'.format(self.conf.cindernative_vol_id,
@ -288,9 +326,22 @@ class BackupJob(Job):
name=self.conf.backup_name,
incremental=self.conf.incremental)
elif backup_media == 'cinder':
LOG.info('Executing cinder snapshot. Volume ID: {0}'.format(
self.conf.cinder_vol_id))
backup_os.backup_cinder_by_glance(self.conf.cinder_vol_id)
if self.conf.cinder_vol_id:
LOG.info('Executing cinder snapshot. Volume ID: {0}'.format(
self.conf.cinder_vol_id))
backup_os.backup_cinder_by_glance(self.conf.cinder_vol_id)
else:
executor = futures.ThreadPoolExecutor(
max_workers=len(self.cinder_vol_ids))
futures_list = []
for instance_id in self.cinder_vol_ids:
LOG.info('Executing cinder snapshot. Volume ID:'
' {0}'.format(instance_id))
futures_list.append(executor.submit(
backup_os.backup_cinder_by_glance(instance_id)))
futures.wait(futures_list, CONF.timeout)
elif backup_media == 'cinderbrick':
LOG.info('Executing cinder volume backup using os-brick. '
'Volume ID: {0}'.format(self.conf.cinderbrick_vol_id))
@ -311,7 +362,9 @@ class RestoreJob(Job):
def _validate(self):
if not any([self.conf.restore_abs_path,
self.conf.nova_inst_id,
self.conf.nova_inst_name,
self.conf.cinder_vol_id,
self.conf.cinder_vol_name,
self.conf.cindernative_vol_id,
self.conf.cinderbrick_vol_id,
self.conf.project_id]):
@ -366,7 +419,8 @@ class RestoreJob(Job):
hostname_backup_name=self.conf.hostname_backup_name,
overwrite=conf.overwrite,
recent_to_date=restore_timestamp)
else:
elif conf.nova_inst_id:
LOG.info("Restoring nova backup. Instance ID: {0}, "
"timestamp: {1} network-id {2}".format(
conf.nova_inst_id,
@ -382,11 +436,36 @@ class RestoreJob(Job):
recent_to_date=restore_timestamp,
backup_media=conf.mode)
else:
for instance_id in self.nova_instance_ids:
LOG.info("Restoring nova backup. Instance ID: {0}, "
"timestamp: {1} network-id {2}".format(
instance_id, restore_timestamp,
conf.nova_restore_network))
hostname_backup_name = os.path.join(
self.conf.hostname_backup_name, instance_id)
self.engine.restore(
hostname_backup_name=hostname_backup_name,
restore_resource=instance_id,
overwrite=conf.overwrite,
recent_to_date=restore_timestamp,
backup_media=conf.mode)
elif conf.backup_media == 'cinder':
LOG.info("Restoring cinder backup from glance. Volume ID: {0}, "
"timestamp: {1}".format(conf.cinder_vol_id,
restore_timestamp))
res.restore_cinder_by_glance(conf.cinder_vol_id, restore_timestamp)
if conf.cinder_vol_id:
LOG.info("Restoring cinder backup from glance. "
"Volume ID: {0}, timestamp: {1}".format(
conf.cinder_vol_id,
restore_timestamp))
res.restore_cinder_by_glance(conf.cinder_vol_id,
restore_timestamp)
else:
for instance_id in self.cinder_vol_ids:
LOG.info("Restoring cinder backup from glance. "
"Volume ID: {0}, timestamp: {1}".format(
instance_id, restore_timestamp))
res.restore_cinder_by_glance(instance_id,
restore_timestamp)
elif conf.backup_media == 'cindernative':
LOG.info("Restoring cinder native backup. Volume ID {0}, Backup ID"
" {1}, timestamp: {2}".format(conf.cindernative_vol_id,
@ -440,13 +519,24 @@ class AdminJob(Job):
timestamp = int(time.mktime(timestamp.timetuple()))
if self.conf.backup_media == 'cinder':
old_backups = self.get_cinder_old_backups(
timestamp,
self.conf.cinder_vol_id
)
self.remove_backup_dirs(old_backups, self.conf.cinder_vol_id)
return {}
if self.conf.cinder_vol_id:
old_backups = self.get_cinder_old_backups(
timestamp,
self.conf.cinder_vol_id
)
self.remove_backup_dirs(old_backups,
self.conf.cinder_vol_id)
return {}
else:
for instance_id in self.cinder_vol_ids:
old_backups = self.get_cinder_old_backups(
timestamp,
instance_id
)
self.remove_backup_dirs(old_backups,
instance_id)
return {}
hostname_backup_name_set = set()
if self.conf.backup_media == 'nova':
@ -457,11 +547,19 @@ class AdminJob(Job):
hostname_backup_name = os.path.join(
self.conf.hostname_backup_name, instance_id)
hostname_backup_name_set.add(hostname_backup_name)
else:
elif self.conf.nova_inst_id:
hostname_backup_name = os.path.join(
self.conf.hostname_backup_name,
self.conf.nova_inst_id)
hostname_backup_name_set.add(hostname_backup_name)
else:
for instance_id in self.nova_instance_ids:
hostname_backup_name = os.path.join(
self.conf.hostname_backup_name,
instance_id)
hostname_backup_name_set.add(hostname_backup_name)
else:
hostname_backup_name_set.add(self.conf.hostname_backup_name)

View File

@ -336,9 +336,11 @@ class BackupOpt1(object):
self.download_limit = -1
self.sql_server_instance = 'Sql Server'
self.cinder_vol_id = ''
self.cinder_vol_name = ''
self.cindernative_vol_id = ''
self.cindernative_backup_id = ''
self.nova_inst_id = ''
self.nova_inst_name = ''
self.lvm_snapperm = 'ro'
self.compression = 'gzip'

View File

@ -45,7 +45,13 @@ class TestNovaEngine(commons.FreezerBaseTestCase):
super(TestNovaEngine, self).setUp()
self.backup_opt = commons.BackupOpt1()
self.project_id = "test-project-id"
self.instance_names = ["instance-1", "instance-2", "instance-3"]
if self.instance_names:
self.instance_ids = [server for server in
self.instance_names
if server == self.backup_opt.nova_inst_name]
self.instance_ids = ["instance-id-1", "instance-id-2", "instance-id-3"]
self.instance_ids_str = json.dumps(self.instance_ids)
servers_list = [FakeServer(instance_id) for instance_id in
self.instance_ids]