def _create_unique_device_link(backup_id, volume_path, volume_id, bckup_mode): """Create a consistent hardlink for the volume block device. Create a consistent hardlink using the backup id so TSM will be able to backup and restore to the same block device. :param backup_id: the backup id :param volume_path: real path of the backup/restore device :param volume_id: Volume id for backup or as restore target :param bckup_mode: TSM backup mode, either 'image' or 'file' :raises: InvalidBackup :returns str -- hardlink path of the volume block device """ if _image_mode(bckup_mode): hardlink_path = utils.make_dev_path('%s-%s' % (CONF.backup_tsm_volume_prefix, backup_id)) else: dir, volname = os.path.split(volume_path) hardlink_path = ('%s/%s-%s' % (dir, CONF.backup_tsm_volume_prefix, backup_id)) _make_link(volume_path, hardlink_path, volume_id) return hardlink_path
def _get_backup_metadata(backup, operation): """Return metadata persisted with backup object.""" svc_metadata = backup['service_metadata'] try: svc_dict = json.loads(svc_metadata) backup_path = svc_dict.get('backup_path') backup_mode = svc_dict.get('backup_mode') except TypeError: # for backwards compatibility vol_prefix = CONF.backup_tsm_volume_prefix backup_id = backup['id'] backup_path = utils.make_dev_path('%s-%s' % (vol_prefix, backup_id)) backup_mode = 'image' if backup_mode not in VALID_BACKUP_MODES: volume_id = backup['volume_id'] backup_id = backup['id'] err = (_('%(op)s: backup %(bck_id)s, volume %(vol_id)s failed. ' 'Backup object has unexpected mode. Image or file ' 'backups supported, actual mode is %(vol_mode)s.') % {'op': operation, 'bck_id': backup_id, 'vol_id': volume_id, 'vol_mode': backup_mode}) LOG.error(err) raise exception.InvalidBackup(reason=err) return backup_path, backup_mode
def _get_backup_metadata(backup, operation): """Return metadata persisted with backup object.""" try: svc_dict = json.loads(backup.service_metadata) backup_path = svc_dict.get('backup_path') backup_mode = svc_dict.get('backup_mode') except TypeError: # for backwards compatibility vol_prefix = CONF.backup_tsm_volume_prefix backup_id = backup['id'] backup_path = utils.make_dev_path('%s-%s' % (vol_prefix, backup_id)) backup_mode = 'image' if backup_mode not in VALID_BACKUP_MODES: volume_id = backup['volume_id'] backup_id = backup['id'] err = (_('%(op)s: backup %(bck_id)s, volume %(vol_id)s failed. ' 'Backup object has unexpected mode. Image or file ' 'backups supported, actual mode is %(vol_mode)s.') % { 'op': operation, 'bck_id': backup_id, 'vol_id': volume_id, 'vol_mode': backup_mode }) LOG.error(err) raise exception.InvalidBackup(reason=err) return backup_path, backup_mode
def _get_backup_metadata(backup, operation): """Return metadata persisted with backup object.""" svc_metadata = backup["service_metadata"] try: svc_dict = json.loads(svc_metadata) backup_path = svc_dict.get("backup_path") backup_mode = svc_dict.get("backup_mode") except TypeError: # for backwards compatibility vol_prefix = CONF.backup_tsm_volume_prefix backup_id = backup["id"] backup_path = utils.make_dev_path("%s-%s" % (vol_prefix, backup_id)) backup_mode = "image" if backup_mode not in VALID_BACKUP_MODES: volume_id = backup["volume_id"] backup_id = backup["id"] err = _( "%(op)s: backup %(bck_id)s, volume %(vol_id)s failed. " "Backup object has unexpected mode. Image or file " "backups supported, actual mode is %(vol_mode)s." ) % {"op": operation, "bck_id": backup_id, "vol_id": volume_id, "vol_mode": backup_mode} LOG.error(err) raise exception.InvalidBackup(reason=err) return backup_path, backup_mode
def delete(self, backup): """Delete the given backup from TSM server. :param backup: backup information for volume :raises InvalidBackup """ delete_attrs = {'Total number of objects deleted': '1'} volume_id = backup['volume_id'] backup_id = backup['id'] LOG.debug('delete started, backup: %s', backup['id']) volume_path = utils.make_dev_path('%s-%s' % (self.volume_prefix, backup_id)) try: out, err = utils.execute('dsmc', 'delete', 'backup', '-quiet', '-noprompt', '-objtype=image', '-deltype=all', '-password=%s' % self.tsm_password, volume_path, run_as_root=True, check_exit_code=False) except processutils.ProcessExecutionError as e: err = (_('delete: %(vol_id)s Failed to run dsmc with ' 'stdout: %(out)s\n stderr: %(err)s') % {'vol_id': volume_id, 'out': e.stdout, 'err': e.stderr}) LOG.error(err) raise exception.InvalidBackup(reason=err) except exception.Error as e: err = (_('restore: %(vol_id)s Failed to run dsmc ' 'due to invalid arguments with ' 'stdout: %(out)s\n stderr: %(err)s') % {'vol_id': volume_id, 'out': e.stdout, 'err': e.stderr}) LOG.error(err) raise exception.InvalidBackup(reason=err) success = self._check_dsmc_output(out, delete_attrs) if not success: err = (_('delete: %(vol_id)s Failed with ' 'stdout: %(out)s\n stderr: %(err)s') % {'vol_id': volume_id, 'out': out, 'err': err}) LOG.error(err) raise exception.InvalidBackup(reason=err) LOG.debug(_('delete %s finished') % backup['id'])
def _create_device_link_using_backupid(self, backup_id, volume_path, volume_id): """Create a consistent hardlink for the volume block device. Create a consistent hardlink using the backup id so TSM will be able to backup and restore to the same block device. :param backup_id: the backup id :param volume_path: real path of the backup/restore device :param volume_id: Volume id for backup or as restore target :raises: InvalidBackup :returns str -- hardlink path of the volume block device """ hardlink_path = utils.make_dev_path('%s-%s' % (self.volume_prefix, backup_id)) self._make_link(volume_path, hardlink_path, volume_id) return hardlink_path
def test_make_dev_path(self, mock_join): self.assertEqual('/dev/xvda', utils.make_dev_path('xvda')) self.assertEqual('/dev/xvdb1', utils.make_dev_path('xvdb', 1)) self.assertEqual('/foo/xvdc1', utils.make_dev_path('xvdc', 1, '/foo'))
def delete(self, backup): """Delete the given backup from TSM server. :param backup: backup information for volume :raises InvalidBackup """ delete_attrs = {'Total number of objects deleted': '1'} volume_id = backup['volume_id'] backup_id = backup['id'] LOG.debug('delete started, backup: %s', backup['id']) volume_path = utils.make_dev_path('%s-%s' % (self.volume_prefix, backup_id)) try: out, err = utils.execute('dsmc', 'delete', 'backup', '-quiet', '-noprompt', '-objtype=image', '-deltype=all', '-password=%s' % self.tsm_password, volume_path, run_as_root=True, check_exit_code=False) except exception.ProcessExecutionError as e: err = (_('delete: %(vol_id)s Failed to run dsmc with ' 'stdout: %(out)s\n stderr: %(err)s') % { 'vol_id': volume_id, 'out': e.stdout, 'err': e.stderr }) LOG.error(err) raise exception.InvalidBackup(reason=err) except exception.Error as e: err = (_('restore: %(vol_id)s Failed to run dsmc ' 'due to invalid arguments with ' 'stdout: %(out)s\n stderr: %(err)s') % { 'vol_id': volume_id, 'out': e.stdout, 'err': e.stderr }) LOG.error(err) raise exception.InvalidBackup(reason=err) success = self._check_dsmc_output(out, delete_attrs) if not success: err = (_('delete: %(vol_id)s Failed with ' 'stdout: %(out)s\n stderr: %(err)s') % { 'vol_id': volume_id, 'out': out, 'err': err }) LOG.error(err) raise exception.InvalidBackup(reason=err) LOG.debug(_('delete %s finished') % backup['id'])