EOF & whitespace
This commit is contained in:
@@ -15,4 +15,3 @@
|
||||
# along with TISBackup. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -25,10 +25,10 @@ from .common import *
|
||||
|
||||
|
||||
class backup_null(backup_generic):
|
||||
"""Null backup to register servers which don't need any backups
|
||||
"""Null backup to register servers which don't need any backups
|
||||
but we still want to know they are taken in account"""
|
||||
type = 'null'
|
||||
|
||||
|
||||
required_params = ['type','server_name','backup_name']
|
||||
optional_params = []
|
||||
|
||||
@@ -44,9 +44,8 @@ class backup_null(backup_generic):
|
||||
return {}
|
||||
def checknagios(self,maxage_hours=30):
|
||||
return (nagiosStateOk,"No backups needs to be performed")
|
||||
|
||||
|
||||
register_driver(backup_null)
|
||||
|
||||
if __name__=='__main__':
|
||||
pass
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ from libtisbackup.common import *
|
||||
|
||||
class backup_oracle(backup_generic):
|
||||
"""Backup a oracle database as zipped file through ssh"""
|
||||
type = 'oracle+ssh'
|
||||
type = 'oracle+ssh'
|
||||
required_params = backup_generic.required_params + ['db_name','private_key', 'userid']
|
||||
optional_params = ['username', 'remote_backup_dir', 'ignore_error_oracle_code']
|
||||
db_name=''
|
||||
@@ -47,7 +47,7 @@ class backup_oracle(backup_generic):
|
||||
ignore_error_oracle_code = [ ]
|
||||
|
||||
def do_backup(self,stats):
|
||||
|
||||
|
||||
self.logger.debug('[%s] Connecting to %s with user %s and key %s',self.backup_name,self.server_name,self.username,self.private_key)
|
||||
try:
|
||||
mykey = paramiko.RSAKey.from_private_key_file(self.private_key)
|
||||
@@ -57,8 +57,8 @@ class backup_oracle(backup_generic):
|
||||
|
||||
self.ssh = paramiko.SSHClient()
|
||||
self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
self.ssh.connect(self.server_name,username=self.username,pkey = mykey,port=self.ssh_port)
|
||||
|
||||
self.ssh.connect(self.server_name,username=self.username,pkey = mykey,port=self.ssh_port)
|
||||
|
||||
t = datetime.datetime.now()
|
||||
self.backup_start_date = t.strftime('%Y%m%d-%Hh%Mm%S')
|
||||
dumpfile= self.remote_backup_dir + '/' + self.db_name + '_' + self.backup_start_date+'.dmp'
|
||||
@@ -71,10 +71,10 @@ class backup_oracle(backup_generic):
|
||||
else:
|
||||
print(('mkdir "%s"' % self.dest_dir))
|
||||
else:
|
||||
raise Exception('backup destination directory already exists : %s' % self.dest_dir)
|
||||
raise Exception('backup destination directory already exists : %s' % self.dest_dir)
|
||||
# dump db
|
||||
stats['status']='Dumping'
|
||||
cmd = "exp '%s' file='%s' grants=y log='%s'"% (self.userid,dumpfile, dumplog)
|
||||
cmd = "exp '%s' file='%s' grants=y log='%s'"% (self.userid,dumpfile, dumplog)
|
||||
self.logger.debug('[%s] Dump DB : %s',self.backup_name,cmd)
|
||||
if not self.dry_run:
|
||||
(error_code,output) = ssh_exec(cmd,ssh=self.ssh)
|
||||
@@ -97,7 +97,7 @@ class backup_oracle(backup_generic):
|
||||
|
||||
# zip the file
|
||||
stats['status']='Zipping'
|
||||
cmd = 'gzip %s' % dumpfile
|
||||
cmd = 'gzip %s' % dumpfile
|
||||
self.logger.debug('[%s] Compress backup : %s',self.backup_name,cmd)
|
||||
if not self.dry_run:
|
||||
(error_code,output) = ssh_exec(cmd,ssh=self.ssh)
|
||||
@@ -120,7 +120,7 @@ class backup_oracle(backup_generic):
|
||||
stats['total_files_count']=1
|
||||
stats['written_files_count']=1
|
||||
stats['total_bytes']=os.stat(localpath).st_size
|
||||
stats['written_bytes']=os.stat(localpath).st_size
|
||||
stats['written_bytes']=os.stat(localpath).st_size
|
||||
stats['log']='gzip dump of DB %s:%s (%d bytes) to %s' % (self.server_name,self.db_name, stats['written_bytes'], localpath)
|
||||
stats['backup_location'] = self.dest_dir
|
||||
stats['status']='RMTemp'
|
||||
@@ -134,7 +134,7 @@ class backup_oracle(backup_generic):
|
||||
|
||||
filelist = os.listdir(self.backup_dir)
|
||||
filelist.sort()
|
||||
p = re.compile('^\d{8,8}-\d{2,2}h\d{2,2}m\d{2,2}$')
|
||||
p = re.compile('^\d{8,8}-\d{2,2}h\d{2,2}m\d{2,2}$')
|
||||
for item in filelist:
|
||||
if p.match(item):
|
||||
dir_name = os.path.join(self.backup_dir,item)
|
||||
|
||||
@@ -30,7 +30,7 @@ from libtisbackup.common import *
|
||||
|
||||
class backup_rsync(backup_generic):
|
||||
"""Backup a directory on remote server with rsync and rsync protocol (requires running remote rsync daemon)"""
|
||||
type = 'rsync'
|
||||
type = 'rsync'
|
||||
required_params = backup_generic.required_params + ['remote_user','remote_dir','rsync_module','password_file']
|
||||
optional_params = backup_generic.optional_params + ['compressionlevel','compression','bwlimit','exclude_list','protect_args','overload_args']
|
||||
|
||||
@@ -46,7 +46,7 @@ class backup_rsync(backup_generic):
|
||||
overload_args = None
|
||||
compressionlevel = 0
|
||||
|
||||
|
||||
|
||||
|
||||
def read_config(self,iniconf):
|
||||
assert(isinstance(iniconf,ConfigParser))
|
||||
@@ -54,7 +54,7 @@ class backup_rsync(backup_generic):
|
||||
if not self.bwlimit and iniconf.has_option('global','bw_limit'):
|
||||
self.bwlimit = iniconf.getint('global','bw_limit')
|
||||
if not self.compressionlevel and iniconf.has_option('global','compression_level'):
|
||||
self.compressionlevel = iniconf.getint('global','compression_level')
|
||||
self.compressionlevel = iniconf.getint('global','compression_level')
|
||||
|
||||
def do_backup(self,stats):
|
||||
if not self.set_lock():
|
||||
@@ -216,7 +216,7 @@ class backup_rsync(backup_generic):
|
||||
raise
|
||||
|
||||
|
||||
finally:
|
||||
finally:
|
||||
self.remove_lock()
|
||||
|
||||
def get_latest_backup(self,current):
|
||||
@@ -225,8 +225,8 @@ class backup_rsync(backup_generic):
|
||||
filelist.sort()
|
||||
filelist.reverse()
|
||||
full = ''
|
||||
r_full = re.compile('^\d{8,8}-\d{2,2}h\d{2,2}m\d{2,2}$')
|
||||
r_partial = re.compile('^\d{8,8}-\d{2,2}h\d{2,2}m\d{2,2}.rsync$')
|
||||
r_full = re.compile('^\d{8,8}-\d{2,2}h\d{2,2}m\d{2,2}$')
|
||||
r_partial = re.compile('^\d{8,8}-\d{2,2}h\d{2,2}m\d{2,2}.rsync$')
|
||||
# we take all latest partials younger than the latest full and the latest full
|
||||
for item in filelist:
|
||||
if r_partial.match(item) and item<current:
|
||||
@@ -245,7 +245,7 @@ class backup_rsync(backup_generic):
|
||||
|
||||
filelist = os.listdir(self.backup_dir)
|
||||
filelist.sort()
|
||||
p = re.compile('^\d{8,8}-\d{2,2}h\d{2,2}m\d{2,2}$')
|
||||
p = re.compile('^\d{8,8}-\d{2,2}h\d{2,2}m\d{2,2}$')
|
||||
for item in filelist:
|
||||
if p.match(item):
|
||||
dir_name = os.path.join(self.backup_dir,item)
|
||||
@@ -288,7 +288,7 @@ class backup_rsync(backup_generic):
|
||||
return False
|
||||
else:
|
||||
self.logger.info("[" + self.backup_name + "] incorrrect lock file : no pid line")
|
||||
return False
|
||||
return False
|
||||
|
||||
|
||||
def set_lock(self):
|
||||
@@ -317,7 +317,7 @@ class backup_rsync(backup_generic):
|
||||
|
||||
class backup_rsync_ssh(backup_rsync):
|
||||
"""Backup a directory on remote server with rsync and ssh protocol (requires rsync software on remote host)"""
|
||||
type = 'rsync+ssh'
|
||||
type = 'rsync+ssh'
|
||||
required_params = backup_generic.required_params + ['remote_user','remote_dir','private_key']
|
||||
optional_params = backup_generic.optional_params + ['compression','bwlimit','ssh_port','exclude_list','protect_args','overload_args', 'cipher_spec']
|
||||
cipher_spec = ''
|
||||
@@ -341,4 +341,3 @@ if __name__=='__main__':
|
||||
b.read_config(cp)
|
||||
b.process_backup()
|
||||
print((b.checknagios()))
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ from .common import *
|
||||
|
||||
class backup_rsync_btrfs(backup_generic):
|
||||
"""Backup a directory on remote server with rsync and btrfs protocol (requires running remote rsync daemon)"""
|
||||
type = 'rsync+btrfs'
|
||||
type = 'rsync+btrfs'
|
||||
required_params = backup_generic.required_params + ['remote_user','remote_dir','rsync_module','password_file']
|
||||
optional_params = backup_generic.optional_params + ['compressionlevel','compression','bwlimit','exclude_list','protect_args','overload_args']
|
||||
|
||||
@@ -46,7 +46,7 @@ class backup_rsync_btrfs(backup_generic):
|
||||
overload_args = None
|
||||
compressionlevel = 0
|
||||
|
||||
|
||||
|
||||
|
||||
def read_config(self,iniconf):
|
||||
assert(isinstance(iniconf,ConfigParser))
|
||||
@@ -54,7 +54,7 @@ class backup_rsync_btrfs(backup_generic):
|
||||
if not self.bwlimit and iniconf.has_option('global','bw_limit'):
|
||||
self.bwlimit = iniconf.getint('global','bw_limit')
|
||||
if not self.compressionlevel and iniconf.has_option('global','compression_level'):
|
||||
self.compressionlevel = iniconf.getint('global','compression_level')
|
||||
self.compressionlevel = iniconf.getint('global','compression_level')
|
||||
|
||||
def do_backup(self,stats):
|
||||
if not self.set_lock():
|
||||
@@ -73,7 +73,7 @@ class backup_rsync_btrfs(backup_generic):
|
||||
returncode = process.returncode
|
||||
if (returncode != 0):
|
||||
self.logger.error("[" + self.backup_name + "] shell program exited with error code: %s"%log)
|
||||
raise Exception("[" + self.backup_name + "] shell program exited with error code " + str(returncode), cmd)
|
||||
raise Exception("[" + self.backup_name + "] shell program exited with error code " + str(returncode), cmd)
|
||||
else:
|
||||
self.logger.info("[" + self.backup_name + "] create btrs volume: %s"%dest_dir)
|
||||
else:
|
||||
@@ -234,7 +234,7 @@ class backup_rsync_btrfs(backup_generic):
|
||||
raise
|
||||
|
||||
|
||||
finally:
|
||||
finally:
|
||||
self.remove_lock()
|
||||
|
||||
def get_latest_backup(self,current):
|
||||
@@ -243,8 +243,8 @@ class backup_rsync_btrfs(backup_generic):
|
||||
filelist.sort()
|
||||
filelist.reverse()
|
||||
full = ''
|
||||
r_full = re.compile('^\d{8,8}-\d{2,2}h\d{2,2}m\d{2,2}$')
|
||||
r_partial = re.compile('^\d{8,8}-\d{2,2}h\d{2,2}m\d{2,2}.rsync$')
|
||||
r_full = re.compile('^\d{8,8}-\d{2,2}h\d{2,2}m\d{2,2}$')
|
||||
r_partial = re.compile('^\d{8,8}-\d{2,2}h\d{2,2}m\d{2,2}.rsync$')
|
||||
# we take all latest partials younger than the latest full and the latest full
|
||||
for item in filelist:
|
||||
if r_partial.match(item) and item<current:
|
||||
@@ -262,7 +262,7 @@ class backup_rsync_btrfs(backup_generic):
|
||||
|
||||
filelist = os.listdir(self.backup_dir)
|
||||
filelist.sort()
|
||||
p = re.compile('^\d{8,8}-\d{2,2}h\d{2,2}m\d{2,2}$')
|
||||
p = re.compile('^\d{8,8}-\d{2,2}h\d{2,2}m\d{2,2}$')
|
||||
for item in filelist:
|
||||
if p.match(item):
|
||||
dir_name = os.path.join(self.backup_dir,item)
|
||||
@@ -305,7 +305,7 @@ class backup_rsync_btrfs(backup_generic):
|
||||
return False
|
||||
else:
|
||||
self.logger.info("[" + self.backup_name + "] incorrrect lock file : no pid line")
|
||||
return False
|
||||
return False
|
||||
|
||||
|
||||
def set_lock(self):
|
||||
@@ -334,7 +334,7 @@ class backup_rsync_btrfs(backup_generic):
|
||||
|
||||
class backup_rsync__btrfs_ssh(backup_rsync_btrfs):
|
||||
"""Backup a directory on remote server with rsync,ssh and btrfs protocol (requires rsync software on remote host)"""
|
||||
type = 'rsync+btrfs+ssh'
|
||||
type = 'rsync+btrfs+ssh'
|
||||
required_params = backup_generic.required_params + ['remote_user','remote_dir','private_key']
|
||||
optional_params = backup_generic.optional_params + ['compression','bwlimit','ssh_port','exclude_list','protect_args','overload_args','cipher_spec']
|
||||
cipher_spec = ''
|
||||
@@ -358,4 +358,3 @@ if __name__=='__main__':
|
||||
b.read_config(cp)
|
||||
b.process_backup()
|
||||
print((b.checknagios()))
|
||||
|
||||
|
||||
@@ -165,4 +165,4 @@ class backup_samba4(backup_generic):
|
||||
self.logger.info('Skipping %s, already registered',dir_name)
|
||||
|
||||
|
||||
register_driver(backup_samba4)
|
||||
register_driver(backup_samba4)
|
||||
|
||||
@@ -152,7 +152,7 @@ class backup_switch(backup_generic):
|
||||
else:
|
||||
child.sendline(self.switch_user)
|
||||
child.expect(".*#")
|
||||
|
||||
|
||||
child.sendline( "terminal datadump")
|
||||
child.expect("#")
|
||||
child.sendline( "show startup-config")
|
||||
@@ -262,4 +262,3 @@ if __name__=='__main__':
|
||||
cp.read('/opt/tisbackup/configtest.ini')
|
||||
b = backup_xva()
|
||||
b.read_config(cp)
|
||||
|
||||
|
||||
+34
-35
@@ -59,15 +59,15 @@ class backup_vmdk(backup_generic):
|
||||
cookie_text = " " + cookie_value + "; $" + cookie_path
|
||||
# Make a cookie
|
||||
cookie = dict()
|
||||
cookie[cookie_name] = cookie_text
|
||||
cookie[cookie_name] = cookie_text
|
||||
return cookie
|
||||
|
||||
|
||||
def download_file(self,url, local_filename, cookie, headers):
|
||||
r = requests.get(url, stream=True, headers=headers,cookies=cookie,verify=False)
|
||||
with open(local_filename, 'wb') as f:
|
||||
for chunk in r.iter_content(chunk_size=1024*1024*64):
|
||||
if chunk:
|
||||
for chunk in r.iter_content(chunk_size=1024*1024*64):
|
||||
if chunk:
|
||||
f.write(chunk)
|
||||
f.flush()
|
||||
return local_filename
|
||||
@@ -78,7 +78,7 @@ class backup_vmdk(backup_generic):
|
||||
try:
|
||||
infos = HttpNfcLease.info
|
||||
device_urls = infos.deviceUrl
|
||||
vmdks = []
|
||||
vmdks = []
|
||||
for device_url in device_urls:
|
||||
deviceId = device_url.key
|
||||
deviceUrlStr = device_url.url
|
||||
@@ -89,7 +89,7 @@ class backup_vmdk(backup_generic):
|
||||
cookie = self.make_compatible_cookie(si._stub.cookie)
|
||||
headers = {'Content-Type': 'application/octet-stream'}
|
||||
self.logger.debug("[%s] exporting disk: %s" %(self.server_name,diskFileName))
|
||||
|
||||
|
||||
self.download_file(diskUrlStr, diskFileName, cookie, headers)
|
||||
vmdks.append({"filename":diskFileName,"id":deviceId})
|
||||
finally:
|
||||
@@ -99,8 +99,8 @@ class backup_vmdk(backup_generic):
|
||||
|
||||
def create_ovf(self,vm,vmdks):
|
||||
ovfDescParams = vim.OvfManager.CreateDescriptorParams()
|
||||
ovf = si.content.ovfManager.CreateDescriptor(vm, ovfDescParams)
|
||||
root = ET.fromstring(ovf.ovfDescriptor)
|
||||
ovf = si.content.ovfManager.CreateDescriptor(vm, ovfDescParams)
|
||||
root = ET.fromstring(ovf.ovfDescriptor)
|
||||
new_id = list(root[0][1].attrib.values())[0][1:3]
|
||||
ovfFiles = []
|
||||
for vmdk in vmdks:
|
||||
@@ -109,14 +109,14 @@ class backup_vmdk(backup_generic):
|
||||
ovfFiles.append(vim.OvfManager.OvfFile(size=os.path.getsize(vmdk['filename']), path=vmdk['filename'], deviceId=id))
|
||||
|
||||
ovfDescParams = vim.OvfManager.CreateDescriptorParams()
|
||||
ovfDescParams.ovfFiles = ovfFiles;
|
||||
ovfDescParams.ovfFiles = ovfFiles;
|
||||
|
||||
ovf = si.content.ovfManager.CreateDescriptor(vm, ovfDescParams)
|
||||
ovf = si.content.ovfManager.CreateDescriptor(vm, ovfDescParams)
|
||||
ovf_filename = vm.name+".ovf"
|
||||
self.logger.debug("[%s] creating ovf file: %s" %(self.server_name,ovf_filename))
|
||||
|
||||
with open(ovf_filename, "w") as f:
|
||||
f.write(ovf.ovfDescriptor)
|
||||
|
||||
with open(ovf_filename, "w") as f:
|
||||
f.write(ovf.ovfDescriptor)
|
||||
return ovf_filename
|
||||
|
||||
def create_ova(self,vm, vmdks, ovf_filename):
|
||||
@@ -131,9 +131,9 @@ class backup_vmdk(backup_generic):
|
||||
|
||||
def clone_vm(self,vm):
|
||||
task = self.wait_task(vm.CreateSnapshot_Task(name="backup",description="Automatic backup "+datetime.now().strftime("%Y-%m-%d %H:%M:%s"),memory=False,quiesce=True))
|
||||
snapshot=task.info.result
|
||||
snapshot=task.info.result
|
||||
prefix_vmclone = self.prefix_clone
|
||||
clone_name = prefix_vmclone + vm.name
|
||||
clone_name = prefix_vmclone + vm.name
|
||||
datastore = '[%s]' % vm.datastore[0].name
|
||||
|
||||
|
||||
@@ -146,16 +146,16 @@ class backup_vmdk(backup_generic):
|
||||
config = vim.vm.ConfigSpec(name=clone_name, memoryMB=vm.summary.config.memorySizeMB, numCPUs=vm.summary.config.numCpu, files=vmx_file)
|
||||
|
||||
hosts = datacenter.hostFolder.childEntity
|
||||
resource_pool = hosts[0].resourcePool
|
||||
resource_pool = hosts[0].resourcePool
|
||||
|
||||
self.wait_task(vmFolder.CreateVM_Task(config=config,pool=resource_pool))
|
||||
self.wait_task(vmFolder.CreateVM_Task(config=config,pool=resource_pool))
|
||||
|
||||
new_vm = [x for x in vmFolder.childEntity if x.name == clone_name][0]
|
||||
|
||||
controller = vim.vm.device.VirtualDeviceSpec()
|
||||
controller.operation = vim.vm.device.VirtualDeviceSpec.Operation.add
|
||||
controller.device = vim.vm.device.VirtualLsiLogicController(busNumber=0,sharedBus='noSharing')
|
||||
controller.device.key = 0
|
||||
controller.device = vim.vm.device.VirtualLsiLogicController(busNumber=0,sharedBus='noSharing')
|
||||
controller.device.key = 0
|
||||
i=0
|
||||
|
||||
vm_devices = []
|
||||
@@ -189,7 +189,7 @@ class backup_vmdk(backup_generic):
|
||||
|
||||
|
||||
|
||||
vm_devices.append(controller)
|
||||
vm_devices.append(controller)
|
||||
|
||||
config.deviceChange=vm_devices
|
||||
self.wait_task(new_vm.ReconfigVM_Task(config))
|
||||
@@ -198,7 +198,7 @@ class backup_vmdk(backup_generic):
|
||||
def wait_task(self,task):
|
||||
while task.info.state in ["queued", "running"]:
|
||||
time.sleep(2)
|
||||
self.logger.debug("[%s] %s",self.server_name,task.info.descriptionId)
|
||||
self.logger.debug("[%s] %s",self.server_name,task.info.descriptionId)
|
||||
return task
|
||||
|
||||
|
||||
@@ -213,7 +213,7 @@ class backup_vmdk(backup_generic):
|
||||
else:
|
||||
print('mkdir "%s"' % dest_dir)
|
||||
else:
|
||||
raise Exception('backup destination directory already exists : %s' % dest_dir)
|
||||
raise Exception('backup destination directory already exists : %s' % dest_dir)
|
||||
os.chdir(dest_dir)
|
||||
user_esx, password_esx, null = open(self.password_file).read().split('\n')
|
||||
|
||||
@@ -237,27 +237,27 @@ class backup_vmdk(backup_generic):
|
||||
if vm.name == self.server_name:
|
||||
vm_is_off = vm.summary.runtime.powerState == "poweredOff"
|
||||
if str2bool(self.halt_vm):
|
||||
vm.ShutdownGuest()
|
||||
vm.ShutdownGuest()
|
||||
vm_is_off = True
|
||||
|
||||
|
||||
if vm_is_off:
|
||||
vmdks = self.export_vmdks(vm)
|
||||
ovf_filename = self.create_ovf(vm, vmdks)
|
||||
ovf_filename = self.create_ovf(vm, vmdks)
|
||||
else:
|
||||
new_vm = self.clone_vm(vm)
|
||||
vmdks = self.export_vmdks(new_vm)
|
||||
ovf_filename = self.create_ovf(vm, vmdks)
|
||||
self.wait_task(new_vm.Destroy_Task())
|
||||
|
||||
self.wait_task(new_vm.Destroy_Task())
|
||||
|
||||
if str2bool(self.create_ovafile):
|
||||
ova_filename = self.create_ova(vm, vmdks, ovf_filename)
|
||||
|
||||
ova_filename = self.create_ova(vm, vmdks, ovf_filename)
|
||||
|
||||
if str2bool(self.halt_vm):
|
||||
vm.PowerOnVM()
|
||||
|
||||
vm.PowerOnVM()
|
||||
|
||||
|
||||
if os.path.exists(dest_dir):
|
||||
for file in os.listdir(dest_dir):
|
||||
for file in os.listdir(dest_dir):
|
||||
stats['written_bytes'] += os.stat(file)[ST_SIZE]
|
||||
stats['total_files_count'] += 1
|
||||
stats['written_files_count'] += 1
|
||||
@@ -266,10 +266,10 @@ class backup_vmdk(backup_generic):
|
||||
stats['written_bytes'] = 0
|
||||
|
||||
stats['backup_location'] = dest_dir
|
||||
|
||||
|
||||
stats['log']='XVA backup from %s OK, %d bytes written' % (self.server_name,stats['written_bytes'])
|
||||
stats['status']='OK'
|
||||
|
||||
stats['status']='OK'
|
||||
|
||||
|
||||
except BaseException as e:
|
||||
stats['status']='ERROR'
|
||||
@@ -279,4 +279,3 @@ class backup_vmdk(backup_generic):
|
||||
|
||||
|
||||
register_driver(backup_vmdk)
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ from .common import *
|
||||
|
||||
class backup_xcp_metadata(backup_generic):
|
||||
"""Backup metatdata of a xcp pool using xe pool-dump-database"""
|
||||
type = 'xcp-dump-metadata'
|
||||
type = 'xcp-dump-metadata'
|
||||
required_params = ['type','server_name','private_key','backup_name']
|
||||
|
||||
def do_backup(self,stats):
|
||||
@@ -60,7 +60,7 @@ class backup_xcp_metadata(backup_generic):
|
||||
stats['total_files_count']=1
|
||||
stats['written_files_count']=1
|
||||
stats['total_bytes']=os.stat(localpath).st_size
|
||||
stats['written_bytes']=os.stat(localpath).st_size
|
||||
stats['written_bytes']=os.stat(localpath).st_size
|
||||
stats['log']='gzip dump of DB %s:%s (%d bytes) to %s' % (self.server_name,'xcp metadata dump', stats['written_bytes'], localpath)
|
||||
stats['backup_location'] = localpath
|
||||
stats['status']='OK'
|
||||
@@ -74,7 +74,7 @@ class backup_xcp_metadata(backup_generic):
|
||||
|
||||
filelist = os.listdir(self.backup_dir)
|
||||
filelist.sort()
|
||||
p = re.compile('^%s-(?P<date>\d{8,8}-\d{2,2}h\d{2,2}m\d{2,2}).dump.gz$' % self.server_name)
|
||||
p = re.compile('^%s-(?P<date>\d{8,8}-\d{2,2}h\d{2,2}m\d{2,2}).dump.gz$' % self.server_name)
|
||||
for item in filelist:
|
||||
sr = p.match(item)
|
||||
if sr:
|
||||
@@ -84,7 +84,7 @@ class backup_xcp_metadata(backup_generic):
|
||||
self.logger.info('Registering %s from %s',file_name,fileisodate(file_name))
|
||||
size_bytes = int(os.popen('du -sb "%s"' % file_name).read().split('\t')[0])
|
||||
self.logger.debug(' Size in bytes : %i',size_bytes)
|
||||
if not self.dry_run:
|
||||
if not self.dry_run:
|
||||
self.dbstat.add(self.backup_name,self.server_name,'',\
|
||||
backup_start=start,backup_end=fileisodate(file_name),status='OK',total_bytes=size_bytes,backup_location=file_name)
|
||||
else:
|
||||
|
||||
+57
-57
@@ -36,7 +36,7 @@ from stat import *
|
||||
from . import XenAPI
|
||||
from .common import *
|
||||
|
||||
if hasattr(ssl, '_create_unverified_context'):
|
||||
if hasattr(ssl, '_create_unverified_context'):
|
||||
ssl._create_default_https_context = ssl._create_unverified_context
|
||||
|
||||
|
||||
@@ -46,23 +46,23 @@ class copy_vm_xcp(backup_generic):
|
||||
|
||||
required_params = backup_generic.required_params + ['server_name','storage_name','password_file','vm_name','network_name']
|
||||
optional_params = backup_generic.optional_params + ['start_vm','max_copies', 'delete_snapshot', 'halt_vm']
|
||||
|
||||
|
||||
start_vm = "no"
|
||||
max_copies = 1
|
||||
halt_vm = "no"
|
||||
halt_vm = "no"
|
||||
delete_snapshot = "yes"
|
||||
|
||||
|
||||
def read_config(self,iniconf):
|
||||
assert(isinstance(iniconf,ConfigParser))
|
||||
backup_generic.read_config(self,iniconf)
|
||||
backup_generic.read_config(self,iniconf)
|
||||
if self.start_vm in 'no' and iniconf.has_option('global','start_vm'):
|
||||
self.start_vm = iniconf.get('global','start_vm')
|
||||
self.start_vm = iniconf.get('global','start_vm')
|
||||
if self.max_copies == 1 and iniconf.has_option('global','max_copies'):
|
||||
self.max_copies = iniconf.getint('global','max_copies')
|
||||
self.max_copies = iniconf.getint('global','max_copies')
|
||||
if self.delete_snapshot == "yes" and iniconf.has_option('global','delete_snapshot'):
|
||||
self.delete_snapshot = iniconf.get('global','delete_snapshot')
|
||||
|
||||
|
||||
|
||||
def copy_vm_to_sr(self, vm_name, storage_name, dry_run, delete_snapshot="yes"):
|
||||
user_xen, password_xen, null = open(self.password_file).read().split('\n')
|
||||
session = XenAPI.Session('https://'+self.server_name)
|
||||
@@ -70,25 +70,25 @@ class copy_vm_xcp(backup_generic):
|
||||
session.login_with_password(user_xen,password_xen)
|
||||
except XenAPI.Failure as error:
|
||||
msg,ip = error.details
|
||||
|
||||
|
||||
if msg == 'HOST_IS_SLAVE':
|
||||
server_name = ip
|
||||
session = XenAPI.Session('https://'+server_name)
|
||||
session.login_with_password(user_xen,password_xen)
|
||||
|
||||
|
||||
session.login_with_password(user_xen,password_xen)
|
||||
|
||||
|
||||
self.logger.debug("[%s] VM (%s) to backup in storage: %s",self.backup_name,vm_name,storage_name)
|
||||
now = datetime.datetime.now()
|
||||
|
||||
|
||||
#get storage opaqueRef
|
||||
try:
|
||||
storage = session.xenapi.SR.get_by_name_label(storage_name)[0]
|
||||
except IndexError as error:
|
||||
result = (1,"error get SR opaqueref %s"%(error))
|
||||
return result
|
||||
|
||||
|
||||
#get vm to copy opaqueRef
|
||||
|
||||
|
||||
#get vm to copy opaqueRef
|
||||
try:
|
||||
vm = session.xenapi.VM.get_by_name_label(vm_name)[0]
|
||||
except IndexError as error:
|
||||
@@ -101,96 +101,96 @@ class copy_vm_xcp(backup_generic):
|
||||
except IndexError as error:
|
||||
result = (1, "error get VM network opaqueref %s" % (error))
|
||||
return result
|
||||
|
||||
|
||||
if str2bool(self.halt_vm):
|
||||
status_vm = session.xenapi.VM.get_power_state(vm)
|
||||
status_vm = session.xenapi.VM.get_power_state(vm)
|
||||
self.logger.debug("[%s] Status of VM: %s",self.backup_name,status_vm)
|
||||
if status_vm == "Running":
|
||||
self.logger.debug("[%s] Shutdown in progress",self.backup_name)
|
||||
if dry_run:
|
||||
print("session.xenapi.VM.clean_shutdown(vm)")
|
||||
print("session.xenapi.VM.clean_shutdown(vm)")
|
||||
else:
|
||||
session.xenapi.VM.clean_shutdown(vm)
|
||||
session.xenapi.VM.clean_shutdown(vm)
|
||||
snapshot = vm
|
||||
else:
|
||||
#do the snapshot
|
||||
#do the snapshot
|
||||
self.logger.debug("[%s] Snapshot in progress",self.backup_name)
|
||||
try:
|
||||
snapshot = session.xenapi.VM.snapshot(vm,"tisbackup-%s"%(vm_name))
|
||||
except XenAPI.Failure as error:
|
||||
result = (1,"error when snapshot %s"%(error))
|
||||
return result
|
||||
|
||||
|
||||
#get snapshot opaqueRef
|
||||
|
||||
|
||||
#get snapshot opaqueRef
|
||||
snapshot = session.xenapi.VM.get_by_name_label("tisbackup-%s"%(vm_name))[0]
|
||||
session.xenapi.VM.set_name_description(snapshot,"snapshot created by tisbackup on : %s"%(now.strftime("%Y-%m-%d %H:%M")))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
vm_backup_name = "zzz-%s-"%(vm_name)
|
||||
|
||||
|
||||
|
||||
|
||||
#Check if old backup exit
|
||||
list_backups = []
|
||||
for vm_ref in session.xenapi.VM.get_all():
|
||||
name_lablel = session.xenapi.VM.get_name_label(vm_ref)
|
||||
if vm_backup_name in name_lablel:
|
||||
list_backups.append(name_lablel)
|
||||
|
||||
|
||||
list_backups.sort()
|
||||
|
||||
|
||||
if len(list_backups) >= 1:
|
||||
|
||||
|
||||
# Shutting last backup if started
|
||||
last_backup_vm = session.xenapi.VM.get_by_name_label(list_backups[-1])[0]
|
||||
if not "Halted" in session.xenapi.VM.get_power_state(last_backup_vm):
|
||||
self.logger.debug("[%s] Shutting down last backup vm : %s", self.backup_name, list_backups[-1] )
|
||||
session.xenapi.VM.hard_shutdown(last_backup_vm)
|
||||
|
||||
|
||||
# Delete oldest backup if exist
|
||||
if len(list_backups) >= int(self.max_copies):
|
||||
for i in range(len(list_backups)-int(self.max_copies)+1):
|
||||
oldest_backup_vm = session.xenapi.VM.get_by_name_label(list_backups[i])[0]
|
||||
if not "Halted" in session.xenapi.VM.get_power_state(oldest_backup_vm):
|
||||
self.logger.debug("[%s] Shutting down old vm : %s", self.backup_name, list_backups[i] )
|
||||
self.logger.debug("[%s] Shutting down old vm : %s", self.backup_name, list_backups[i] )
|
||||
session.xenapi.VM.hard_shutdown(oldest_backup_vm)
|
||||
|
||||
|
||||
try:
|
||||
self.logger.debug("[%s] Deleting old vm : %s", self.backup_name, list_backups[i])
|
||||
for vbd in session.xenapi.VM.get_VBDs(oldest_backup_vm):
|
||||
if session.xenapi.VBD.get_type(vbd) == 'CD'and session.xenapi.VBD.get_record(vbd)['empty'] == False:
|
||||
session.xenapi.VBD.eject(vbd)
|
||||
session.xenapi.VBD.eject(vbd)
|
||||
else:
|
||||
vdi = session.xenapi.VBD.get_VDI(vbd)
|
||||
if not 'NULL' in vdi:
|
||||
session.xenapi.VDI.destroy(vdi)
|
||||
|
||||
session.xenapi.VM.destroy(oldest_backup_vm)
|
||||
|
||||
session.xenapi.VM.destroy(oldest_backup_vm)
|
||||
except XenAPI.Failure as error:
|
||||
result = (1,"error when destroy old backup vm %s"%(error))
|
||||
return result
|
||||
|
||||
|
||||
|
||||
|
||||
self.logger.debug("[%s] Copy %s in progress on %s",self.backup_name,vm_name,storage_name)
|
||||
try:
|
||||
backup_vm = session.xenapi.VM.copy(snapshot,vm_backup_name+now.strftime("%Y-%m-%d %H:%M"),storage)
|
||||
except XenAPI.Failure as error:
|
||||
result = (1,"error when copy %s"%(error))
|
||||
return result
|
||||
|
||||
|
||||
|
||||
|
||||
# define VM as a template
|
||||
session.xenapi.VM.set_is_a_template(backup_vm,False)
|
||||
|
||||
|
||||
#change the network of the new VM
|
||||
try:
|
||||
vifDestroy = session.xenapi.VM.get_VIFs(backup_vm)
|
||||
except IndexError as error:
|
||||
result = (1,"error get VIF opaqueref %s"%(error))
|
||||
return result
|
||||
|
||||
|
||||
|
||||
|
||||
for i in vifDestroy:
|
||||
vifRecord = session.xenapi.VIF.get_record(i)
|
||||
session.xenapi.VIF.destroy(i)
|
||||
@@ -218,13 +218,13 @@ class copy_vm_xcp(backup_generic):
|
||||
except Exception as error:
|
||||
result = (1,error)
|
||||
return result
|
||||
|
||||
|
||||
|
||||
|
||||
if self.start_vm in ['true', '1', 't', 'y', 'yes', 'oui']:
|
||||
session.xenapi.VM.start(backup_vm,False,True)
|
||||
|
||||
|
||||
session.xenapi.VM.set_name_description(backup_vm,"snapshot created by tisbackup on : %s"%(now.strftime("%Y-%m-%d %H:%M")))
|
||||
|
||||
|
||||
size_backup = 0
|
||||
for vbd in session.xenapi.VM.get_VBDs(backup_vm):
|
||||
if session.xenapi.VBD.get_type(vbd) == 'CD' and session.xenapi.VBD.get_record(vbd)['empty'] == False:
|
||||
@@ -233,11 +233,11 @@ class copy_vm_xcp(backup_generic):
|
||||
vdi = session.xenapi.VBD.get_VDI(vbd)
|
||||
if not 'NULL' in vdi:
|
||||
size_backup = size_backup + int(session.xenapi.VDI.get_record(vdi)['physical_utilisation'])
|
||||
|
||||
|
||||
result = (0,size_backup)
|
||||
if self.delete_snapshot == 'no':
|
||||
return result
|
||||
|
||||
|
||||
#Disable automatic boot
|
||||
if 'auto_poweron' in session.xenapi.VM.get_other_config(backup_vm):
|
||||
session.xenapi.VM.remove_from_other_config(backup_vm, "auto_poweron")
|
||||
@@ -260,25 +260,25 @@ class copy_vm_xcp(backup_generic):
|
||||
if status_vm == "Running":
|
||||
self.logger.debug("[%s] Starting in progress",self.backup_name)
|
||||
if dry_run:
|
||||
print("session.xenapi.VM.start(vm,False,True)")
|
||||
print("session.xenapi.VM.start(vm,False,True)")
|
||||
else:
|
||||
session.xenapi.VM.start(vm,False,True)
|
||||
|
||||
|
||||
return result
|
||||
|
||||
|
||||
|
||||
|
||||
def do_backup(self,stats):
|
||||
try:
|
||||
timestamp = int(time.time())
|
||||
cmd = self.copy_vm_to_sr(self.vm_name, self.storage_name, self.dry_run, delete_snapshot=self.delete_snapshot)
|
||||
|
||||
|
||||
if cmd[0] == 0:
|
||||
timeExec = int(time.time()) - timestamp
|
||||
stats['log']='copy of %s to an other storage OK' % (self.backup_name)
|
||||
stats['status']='OK'
|
||||
stats['total_files_count'] = 1
|
||||
stats['total_bytes'] = cmd[1]
|
||||
|
||||
|
||||
stats['backup_location'] = self.storage_name
|
||||
else:
|
||||
stats['status']='ERROR'
|
||||
|
||||
Reference in New Issue
Block a user