Add ftp support framework in freezer

The patch adds ftp support framework in freezer.

ref: https://storyboard.openstack.org/#!/story/2004332

Change-Id: I68553e1b0d98997af4bff4ce57da81b1fb835491
Story: #2004332
Task: #27917
This commit is contained in:
gengchc2 2018-11-20 18:42:46 -08:00
parent 1b502f2b2b
commit 93dbf58160
7 changed files with 132 additions and 17 deletions

View File

@ -37,6 +37,7 @@ home = os.path.expanduser("~")
DEFAULT_LVM_SNAPSIZE = '1G'
DEFAULT_LVM_MOUNT_BASEDIR = '/var/lib/freezer'
DEFAULT_LVM_SNAP_BASENAME = 'freezer_backup_snap'
DEFAULT_FTP_PORT = 21
DEFAULT_SSH_PORT = 22
_DEFAULT_LOG_LEVELS = ['amqp=WARN', 'amqplib=WARN', 'boto=WARN',
@ -86,7 +87,8 @@ DEFAULT_PARAMS = {
'incremental': None, 'consistency_check': False,
'consistency_checksum': None, 'nova_restore_network': None,
'cindernative_backup_id': None, 'sync': True, 'engine_name': 'tar',
'timeout': 120, 'project_id': None,
'timeout': 120, 'project_id': None, 'ftp_username': '',
'ftp_password': '', 'ftp_host': '', 'ftp_port': DEFAULT_FTP_PORT,
}
_COMMON = [
@ -435,12 +437,12 @@ _COMMON = [
cfg.StrOpt('storage',
dest='storage',
default=DEFAULT_PARAMS['storage'],
choices=['local', 'swift', 'ssh', 's3'],
help="Storage for backups. Can be Swift, Local, SSH and S3 "
"now. Swift is default storage now. Local stores backups"
"on the same defined path, swift will store files in "
"container, and s3 will store files in bucket in S3 "
"compatible storage."
choices=['local', 'swift', 'ssh', 's3', 'ftp', 'ftps'],
help="Storage for backups. Can be Swift, Local, SSH(SFTP), "
"FTP, FTPS and S3 now. Swift is default storage now. "
"Local stores backups on the same defined path, "
"swift will store files in container, and S3 will "
"store files in bucket in S3 compatible storage."
),
cfg.StrOpt('access-key',
dest='access_key',
@ -465,22 +467,22 @@ _COMMON = [
cfg.StrOpt('ssh-password',
dest='ssh_password',
default=DEFAULT_PARAMS['ssh_password'],
help="Remote password for ssh(sftp) storage"
help="Remote password for SSH(SFTP) storage"
),
cfg.StrOpt('ssh-username',
dest='ssh_username',
default=DEFAULT_PARAMS['ssh_username'],
help="Remote username for ssh(sftp) storage only"
help="Remote username for SSH(SFTP)) storage only"
),
cfg.StrOpt('ssh-host',
dest='ssh_host',
default=DEFAULT_PARAMS['ssh_host'],
help="Remote host for ssh(sftp) storage only"
help="Remote host for SSH(SFTP) storage only"
),
cfg.IntOpt('ssh-port',
dest='ssh_port',
default=DEFAULT_PARAMS['ssh_port'],
help="Remote port for ssh(sftp) storage"
help="Remote port for SSH(SFTP) storage"
" only (default 22)"
),
cfg.StrOpt('config',
@ -542,6 +544,26 @@ _COMMON = [
"If set action to admin and set the parameter, "
"it should keep the last N fullbackups, "
"other backups should be deleted"),
cfg.StrOpt('ftp-password',
dest='ftp_password',
default=DEFAULT_PARAMS['ftp_password'],
help="Remote password for FTP, FTPS storage"
),
cfg.StrOpt('ftp-username',
dest='ftp_username',
default=DEFAULT_PARAMS['ftp_username'],
help="Remote username for FTP, FTPS storage"
),
cfg.StrOpt('ftp-host',
dest='ftp_host',
default=DEFAULT_PARAMS['ftp_host'],
help="Remote host for FTP, FTPS storage"
),
cfg.IntOpt('ftp-port',
dest='ftp_port',
default=DEFAULT_PARAMS['ftp_port'],
help="Remote port for FTP, FTPS storage (default 21)"
),
]

View File

@ -77,7 +77,7 @@ class NovaEngine(engine.BackupEngine):
bucket_name=bucket_name,
key=object_name
)['Body'].read()
elif self.storage._type in ['local', 'ssh']:
elif self.storage._type in ['local', 'ssh', 'ftp', 'ftps']:
backup_basepath = os.path.join(self.storage.storage_path,
'project_' + project_id)
with self.storage.open(backup_basepath, 'rb') as backup_file:
@ -186,7 +186,7 @@ class NovaEngine(engine.BackupEngine):
key=object_name,
data=data
)
elif self.storage._type in ['local', 'ssh']:
elif self.storage._type in ['local', 'ssh', 'ftp', 'ftps']:
backup_basepath = os.path.join(self.storage.storage_path,
"project_" + project_id)
with self.storage.open(backup_basepath, 'wb') as backup_file:

View File

@ -593,7 +593,8 @@ class AdminJob(Job):
self.storage.segments,
cinder_vol_id
)
elif self.storage.type in ['local', 'ssh', 's3']:
elif self.storage.type in \
['local', 'ssh', 's3', 'ftp', 'ftps']:
path_prefix = "{0}/{1}".format(
self.storage.storage_path,
cinder_vol_id

View File

@ -26,6 +26,7 @@ import sys
from oslo_config import cfg
from oslo_log import log
from oslo_utils import importutils
from freezer.common import client_manager
from freezer.common import config as freezer_config
@ -229,6 +230,14 @@ def storage_from_dict(backup_args, max_segment_size):
int(backup_args['ssh_port']),
max_segment_size=max_segment_size,
ssh_key_path=backup_args['ssh_key'])
elif storage_name in ["ftp", "ftps"]:
args = [container, backup_args['ftp_password'],
backup_args['ftp_username'],
backup_args['ftp_host'], int(backup_args['ftp_port']),
max_segment_size]
storage = importutils.import_object(
"freezer.storage.{0}.{1}Storage".format(
storage_name, storage_name.capitalize()), *args)
else:
raise Exception("No storage found for name {0}".format(
backup_args['storage']))

View File

@ -62,12 +62,13 @@ class RestoreOs(object):
elif self.storage.type == "local":
path = "{0}/{1}".format(self.container, path)
backups = os.listdir(os.path.abspath(path))
elif self.storage.type == "ssh":
elif self.storage.type in ["ssh", 'ftp', 'ftps']:
path = "{0}/{1}".format(self.container, path)
backups = self.storage.listdir(path)
else:
msg = ("{} storage type is not supported at the moment."
" Try local, swift or ssh".format(self.storage.type))
" Try local, SWIFT, SSH(SFTP), FTP or FTPS ".
format(self.storage.type))
print(msg)
raise BaseException(msg)
backups = list(filter(lambda x: x >= restore_from_timestamp, backups))
@ -160,7 +161,7 @@ class RestoreOs(object):
disk_format="raw",
data=data)
return info, image
elif self.storage.type == 'ssh':
elif self.storage.type in ['ssh', 'ftp', 'ftps']:
image_file = "{0}/{1}/{2}/{3}".format(self.container, path,
backup, path)
metadata_file = "{0}/{1}/{2}/metadata".format(self.container,

41
freezer/storage/ftp.py Normal file
View File

@ -0,0 +1,41 @@
"""
(c) Copyright 2018 ZTE Corporation.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
# import errno
# import ftplib
# import os
# import shutil
# import socket
# import tempfile
from oslo_log import log
from freezer.storage import fslike
# from freezer.utils import utils
CHUNK_SIZE = 32768
LOG = log.getLogger(__name__)
class FtpStorage(fslike.FsLikeStorage):
"""
:type ftp: paramiko.SFTPClient
"""
_type = 'ftp'
def __init__(self, storage_path, remote_pwd,
remote_username, remote_ip, port, max_segment_size):
pass

41
freezer/storage/ftps.py Normal file
View File

@ -0,0 +1,41 @@
"""
(c) Copyright 2018 ZTE Corporation.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
# import errno
# import ftplib
# import os
# import shutil
# import socket
# import tempfile
from oslo_log import log
from freezer.storage import fslike
# from freezer.utils import utils
CHUNK_SIZE = 32768
LOG = log.getLogger(__name__)
class FtpsStorage(fslike.FsLikeStorage):
"""
:type ftps: paramiko.SFTPClient
"""
_type = 'ftps'
def __init__(self, storage_path, remote_pwd,
remote_username, remote_ip, port, max_segment_size):
pass