Meilleur gestion des backups XenServer

This commit is contained in:
ssamson-tis 2014-07-25 15:04:10 +02:00
parent 0f45474138
commit 639bb15460
2 changed files with 170 additions and 78 deletions

View File

@ -17,7 +17,7 @@
# along with TISBackup. If not, see <http://www.gnu.org/licenses/>. # along with TISBackup. If not, see <http://www.gnu.org/licenses/>.
# #
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
from __future__ import with_statement
import os import os
import datetime import datetime
from common import * from common import *
@ -29,9 +29,10 @@ import os.path
import os import os
import datetime import datetime
import select import select
import urllib2 import urllib
import base64
import socket import socket
import tarfile
import hashlib
from stat import * from stat import *
@ -40,9 +41,30 @@ class backup_xva(backup_generic):
type = 'xen-xva' type = 'xen-xva'
required_params = backup_generic.required_params + ['xcphost','password_file','server_name'] required_params = backup_generic.required_params + ['xcphost','password_file','server_name']
optional_params = backup_generic.optional_params + ['excluded_vbds','remote_user','private_key'] optional_params = backup_generic.optional_params + ['enable_https', 'halt_vm', 'verify_export']
def export_xva(self, vdi_name, filename, dry_run): enable_https = "no"
halt_vm = "no"
verify_export = "no"
def str2bool(self,v):
if type(v) != bool:
return v.lower() in ("yes", "true", "t", "1")
def verify_export_xva(self,filename):
self.logger.debug("[%s] Verify xva export integrity",self.server_name)
tar = tarfile.open(filename)
members = tar.getmembers()
for tarinfo in members:
if re.search('^[0-9]*$',os.path.basename(tarinfo.name)):
sha1sum = hashlib.sha1(tar.extractfile(tarinfo).read()).hexdigest()
sha1sum2 = tar.extractfile(tarinfo.name+'.checksum').read()
if not sha1sum == sha1sum2:
raise Exception("File corrupt")
tar.close()
def export_xva(self, vdi_name, filename, halt_vm,dry_run,enable_https=True):
user_xen, password_xen, null = open(self.password_file).read().split('\n') user_xen, password_xen, null = open(self.password_file).read().split('\n')
session = XenAPI.Session('https://'+self.xcphost) session = XenAPI.Session('https://'+self.xcphost)
@ -56,45 +78,89 @@ class backup_xva(backup_generic):
session = XenAPI.Session('https://'+xcphost) session = XenAPI.Session('https://'+xcphost)
session.login_with_password(user_xen,password_xen) session.login_with_password(user_xen,password_xen)
if not session.xenapi.VM.get_by_name_label(vdi_name):
return "bad VM name: %s" % vdi_name
vm = session.xenapi.VM.get_by_name_label(vdi_name)[0] vm = session.xenapi.VM.get_by_name_label(vdi_name)[0]
status_vm = session.xenapi.VM.get_power_state(vm) status_vm = session.xenapi.VM.get_power_state(vm)
self.logger.debug("[%s] Check if previous fail backups exist",vdi_name)
backups_fail = files = [f for f in os.listdir(self.backup_dir) if f.startswith(vdi_name) and f.endswith(".tmp")]
for backup_fail in backups_fail:
self.logger.debug('[%s] Delete backup "%s"', vdi_name, backup_fail)
os.unlink(os.path.join(self.backup_dir, backup_fail))
#add snapshot option
if self.str2bool(halt_vm) == False:
self.logger.debug("[%s] Check if previous tisbackups snapshots exist",vdi_name)
old_snapshots = session.xenapi.VM.get_by_name_label("tisbackup-%s"%(vdi_name))
for old_snapshot in old_snapshots:
self.logger.debug("[%s] Destroy snapshot %s",vdi_name,session.xenapi.VM.get_name_description(old_snapshot))
try:
for vbd in session.xenapi.VM.get_VBDs(old_snapshot):
if session.xenapi.VBD.get_type(vbd) == 'CD' and session.xenapi.VBD.get_record(vbd)['empty'] == False:
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(old_snapshot)
except XenAPI.Failure, error:
return("error when destroy snapshot %s"%(error))
now = datetime.datetime.now()
self.logger.debug("[%s] Snapshot in progress",vdi_name)
try:
snapshot = session.xenapi.VM.snapshot(vm,"tisbackup-%s"%(vdi_name))
except XenAPI.Failure, error:
return("error when snapshot %s"%(error))
#get snapshot opaqueRef
vm = session.xenapi.VM.get_by_name_label("tisbackup-%s"%(vdi_name))[0]
session.xenapi.VM.set_name_description(snapshot,"snapshot created by tisbackup on : %s"%(now.strftime("%Y-%m-%d %H:%M")))
else:
self.logger.debug("[%s] Status of VM: %s",self.backup_name,status_vm) self.logger.debug("[%s] Status of VM: %s",self.backup_name,status_vm)
if status_vm == "Running": if status_vm == "Running":
self.logger.debug("[%s] Shudown in progress",self.backup_name) self.logger.debug("[%s] Shudown in progress",self.backup_name)
if dry_run: if dry_run:
print "session.xenapi.VM.clean_shutdown(vm)" print "session.xenapi.VM.clean_shutdown(vm)"
else: else:
session.xenapi.VM.clean_shutdown(vm) session.xenapi.VM.clean_shutdown(vm)
try: try:
try: try:
filename_temp = filename+".tmp"
self.logger.debug("[%s] Copy in progress",self.backup_name) self.logger.debug("[%s] Copy in progress",self.backup_name)
socket.setdefaulttimeout(120) socket.setdefaulttimeout(120)
auth = base64.encodestring("%s:%s" % (user_xen, password_xen)).strip() if self.str2bool(enable_https) == True:
url = "https://"+self.xcphost+"/export?uuid="+session.xenapi.VM.get_uuid(vm) url = "https://"+user_xen+":"+password_xen+"@"+self.xcphost+"/export?uuid="+session.xenapi.VM.get_uuid(vm)
request = urllib2.Request(url)
request.add_header("Authorization", "Basic %s" % auth)
result = urllib2.urlopen(request)
if dry_run:
print "request = urllib2.Request(%s)" % url
print 'outputfile = open(%s, "wb")' % filename
else: else:
outputfile = open(filename, "wb") url = "http://"+user_xen+":"+password_xen+"@"+self.xcphost+"/export?uuid="+session.xenapi.VM.get_uuid(vm)
for line in result: urllib.urlretrieve(url, filename_temp)
outputfile.write(line) urllib.urlcleanup()
outputfile.close()
except: except:
if os.path.exists(filename): if os.path.exists(filename_temp):
os.unlink(filename) os.unlink(filename_temp)
raise raise
finally: finally:
if status_vm == "Running": if self.str2bool(halt_vm) == False:
self.logger.debug("[%s] Destroy snapshot",'tisbackup-%s'%(vdi_name))
try:
for vbd in session.xenapi.VM.get_VBDs(snapshot):
if session.xenapi.VBD.get_type(vbd) == 'CD' and session.xenapi.VBD.get_record(vbd)['empty'] == False:
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(snapshot)
except XenAPI.Failure, error:
return("error when destroy snapshot %s"%(error))
elif status_vm == "Running":
self.logger.debug("[%s] Starting in progress",self.backup_name) self.logger.debug("[%s] Starting in progress",self.backup_name)
if dry_run: if dry_run:
print "session.xenapi.Async.VM.start(vm,False,True)" print "session.xenapi.Async.VM.start(vm,False,True)"
@ -103,13 +169,15 @@ class backup_xva(backup_generic):
session.logout() session.logout()
if os.path.exists(filename): if os.path.exists(filename_temp):
import tarfile tar = tarfile.open(filename_temp)
tar = tarfile.open(filename)
if not tar.getnames(): if not tar.getnames():
unlink(filename) unlink(filename_temp)
return("Tar error") return("Tar error")
tar.close() tar.close()
if self.str2bool(self.verify_export):
self.verify_export_xva(filename_temp)
os.rename(filename_temp,filename)
return(0) return(0)
@ -122,7 +190,7 @@ class backup_xva(backup_generic):
options = [] options = []
options_params = " ".join(options) options_params = " ".join(options)
cmd = self.export_xva( self.server_name, dest_filename, self.dry_run) cmd = self.export_xva( vdi_name= self.server_name,filename= dest_filename, halt_vm= self.halt_vm, enable_https=self.enable_https, dry_run= self.dry_run)
if os.path.exists(dest_filename): if os.path.exists(dest_filename):
stats['written_bytes'] = os.stat(dest_filename)[ST_SIZE] stats['written_bytes'] = os.stat(dest_filename)[ST_SIZE]
stats['total_files_count'] = 1 stats['total_files_count'] = 1
@ -136,10 +204,7 @@ class backup_xva(backup_generic):
stats['log']='XVA backup from %s OK, %d bytes written' % (self.server_name,stats['written_bytes']) stats['log']='XVA backup from %s OK, %d bytes written' % (self.server_name,stats['written_bytes'])
stats['status']='OK' stats['status']='OK'
else: else:
stats['status']='ERROR' raise Exception(cmd)
stats['log']=cmd
except BaseException , e: except BaseException , e:
stats['status']='ERROR' stats['status']='ERROR'
@ -162,4 +227,3 @@ if __name__=='__main__':
cp.read('/opt/tisbackup/configtest.ini') cp.read('/opt/tisbackup/configtest.ini')
b = backup_xva() b = backup_xva()
b.read_config(cp) b.read_config(cp)

View File

@ -45,6 +45,7 @@ class copy_vm_xcp(backup_generic):
start_vm = "no" start_vm = "no"
max_copies = 1 max_copies = 1
def read_config(self,iniconf): def read_config(self,iniconf):
assert(isinstance(iniconf,ConfigParser)) assert(isinstance(iniconf,ConfigParser))
backup_generic.read_config(self,iniconf) backup_generic.read_config(self,iniconf)
@ -55,7 +56,6 @@ class copy_vm_xcp(backup_generic):
def copy_vm_to_sr(self, vm_name, storage_name, dry_run): def copy_vm_to_sr(self, vm_name, storage_name, dry_run):
user_xen, password_xen, null = open(self.password_file).read().split('\n') user_xen, password_xen, null = open(self.password_file).read().split('\n')
session = XenAPI.Session('https://'+self.server_name) session = XenAPI.Session('https://'+self.server_name)
try: try:
@ -76,20 +76,25 @@ class copy_vm_xcp(backup_generic):
try: try:
storage = session.xenapi.SR.get_by_name_label(storage_name)[0] storage = session.xenapi.SR.get_by_name_label(storage_name)[0]
except IndexError,error: except IndexError,error:
return("error get storage opaqueref %s"%(error)) result = (1,"error get VM opaqueref %s"%(error))
return result
#get vm to copy opaqueRef #get vm to copy opaqueRef
try: try:
vm = session.xenapi.VM.get_by_name_label(vm_name)[0] vm = session.xenapi.VM.get_by_name_label(vm_name)[0]
except IndexError,error: except IndexError,error:
return("error get VM opaqueref %s"%(error)) result = (1,"error get VM opaqueref %s"%(error))
return result
#do the snapshot #do the snapshot
self.logger.debug("[%s] Snapshot in progress",self.backup_name) self.logger.debug("[%s] Snapshot in progress",self.backup_name)
try: try:
snapshot = session.xenapi.VM.snapshot(vm,"tisbackup-%s"%(vm_name)) snapshot = session.xenapi.VM.snapshot(vm,"tisbackup-%s"%(vm_name))
except XenAPI.Failure, error: except XenAPI.Failure, error:
return("error when snapshot %s"%(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] snapshot = session.xenapi.VM.get_by_name_label("tisbackup-%s"%(vm_name))[0]
@ -128,20 +133,25 @@ class copy_vm_xcp(backup_generic):
try: try:
self.logger.debug("[%s] Deleting old vm : %s", self.backup_name, list_backups[i]) 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): 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)
else:
vdi = session.xenapi.VBD.get_VDI(vbd) vdi = session.xenapi.VBD.get_VDI(vbd)
if not 'NULL' in vdi: if not 'NULL' in vdi:
session.xenapi.VDI.destroy(vdi) session.xenapi.VDI.destroy(vdi)
session.xenapi.VM.destroy(oldest_backup_vm) session.xenapi.VM.destroy(oldest_backup_vm)
except XenAPI.Failure, error: except XenAPI.Failure, error:
return("error when destroy old backup vm %s"%(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) self.logger.debug("[%s] Copy %s in progress on %s",self.backup_name,vm_name,storage_name)
try: try:
backup_vm = session.xenapi.VM.copy(snapshot,vm_backup_name+now.strftime("%Y-%m-%d %H:%M"),storage) backup_vm = session.xenapi.VM.copy(snapshot,vm_backup_name+now.strftime("%Y-%m-%d %H:%M"),storage)
except XenAPI.Failure, error: except XenAPI.Failure, error:
return("error when copy %s"%(error)) result = (1,"error when copy %s"%(error))
return result
# define VM as a template # define VM as a template
@ -151,7 +161,9 @@ class copy_vm_xcp(backup_generic):
try: try:
vifDestroy = session.xenapi.VM.get_VIFs(backup_vm) vifDestroy = session.xenapi.VM.get_VIFs(backup_vm)
except IndexError,error: except IndexError,error:
return("error get VIF opaqueref %s"%(error)) result = (1,"error get VIF opaqueref %s"%(error))
return result
for i in vifDestroy: for i in vifDestroy:
vifRecord = session.xenapi.VIF.get_record(i) vifRecord = session.xenapi.VIF.get_record(i)
@ -179,46 +191,62 @@ class copy_vm_xcp(backup_generic):
try: try:
session.xenapi.VIF.create(data) session.xenapi.VIF.create(data)
except Exception, error: except Exception, error:
return(error) result = (1,error)
return result
if self.start_vm in ['true', '1', 't', 'y', 'yes', 'oui']: if self.start_vm in ['true', '1', 't', 'y', 'yes', 'oui']:
session.xenapi.VM.start(backup_vm,False,True) 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"))) 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:
session.xenapi.VBD.eject(vbd)
else:
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'])
#delete the snapshot #delete the snapshot
try: try:
for vbd in session.xenapi.VM.get_VBDs(snapshot):
if session.xenapi.VBD.get_type(vbd) == 'CD' and session.xenapi.VBD.get_record(vbd)['empty'] == False:
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(snapshot) session.xenapi.VM.destroy(snapshot)
except XenAPI.Failure, error: except XenAPI.Failure, error:
return("error when destroy snapshot %s"%(error)) result = (1,"error when destroy snapshot %s"%(error))
return result
return(0) result = (0,size_backup)
return result
def do_backup(self,stats): def do_backup(self,stats):
try: try:
timestamp = int(time.time()) timestamp = int(time.time())
cmd = self.copy_vm_to_sr(self.vm_name, self.storage_name, self.dry_run) cmd = self.copy_vm_to_sr(self.vm_name, self.storage_name, self.dry_run)
if cmd == 0:
if cmd[0] == 0:
timeExec = int(time.time()) - timestamp timeExec = int(time.time()) - timestamp
stats['log']='copy of %s to an other storage OK' % (self.backup_name) stats['log']='copy of %s to an other storage OK' % (self.backup_name)
stats['status']='OK' stats['status']='OK'
stats['total_files_count'] = 1 stats['total_files_count'] = 1
stats['total_bytes'] = cmd[1]
stats['backup_location'] = self.storage_name stats['backup_location'] = self.storage_name
else: else:
stats['status']='ERROR' stats['status']='ERROR'
stats['log']=cmd stats['log']=cmd[1]
except BaseException,e: except BaseException,e:
stats['status']='ERROR' stats['status']='ERROR'
stats['log']=str(e) stats['log']=str(e)
raise raise
register_driver(copy_vm_xcp) register_driver(copy_vm_xcp)