Tiny optimization for copy_vm_xcp / backup_xva schemes
Both methods create a snap and make a copy of it, and both methods ought to be used in the same backup process. To avoid overwhelming the storage, it is now possible to avoid deleting a snap in copy_vm_xcp (delete_snapshot=no) so that it gets reused in backup_xva (reuse_snapshot=yes). Requested by Yvan.
This commit is contained in:
parent
4d054189c7
commit
059c94797a
@ -41,12 +41,12 @@ 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 + ['enable_https', 'halt_vm', 'verify_export']
|
optional_params = backup_generic.optional_params + ['enable_https', 'halt_vm', 'verify_export', 'reuse_snapshot']
|
||||||
|
|
||||||
enable_https = "no"
|
enable_https = "no"
|
||||||
halt_vm = "no"
|
halt_vm = "no"
|
||||||
verify_export = "no"
|
verify_export = "no"
|
||||||
|
reuse_snapshot = "no"
|
||||||
|
|
||||||
def str2bool(self,v):
|
def str2bool(self,v):
|
||||||
if type(v) != bool:
|
if type(v) != bool:
|
||||||
@ -64,7 +64,7 @@ class backup_xva(backup_generic):
|
|||||||
raise Exception("File corrupt")
|
raise Exception("File corrupt")
|
||||||
tar.close()
|
tar.close()
|
||||||
|
|
||||||
def export_xva(self, vdi_name, filename, halt_vm,dry_run,enable_https=True):
|
def export_xva(self, vdi_name, filename, halt_vm,dry_run,enable_https=True, reuse_snapshot="no"):
|
||||||
|
|
||||||
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)
|
||||||
@ -96,30 +96,38 @@ class backup_xva(backup_generic):
|
|||||||
if self.str2bool(halt_vm) == False:
|
if self.str2bool(halt_vm) == False:
|
||||||
self.logger.debug("[%s] Check if previous tisbackups snapshots exist",vdi_name)
|
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))
|
old_snapshots = session.xenapi.VM.get_by_name_label("tisbackup-%s"%(vdi_name))
|
||||||
for old_snapshot in old_snapshots:
|
self.logger.debug("[%s] Old snaps count %s", vdi_name, len(old_snapshots))
|
||||||
|
|
||||||
self.logger.debug("[%s] Destroy snapshot %s",vdi_name,session.xenapi.VM.get_name_description(old_snapshot))
|
if len(old_snapshots) == 1 and self.str2bool(reuse_snapshot) == True:
|
||||||
|
snapshot = old_snapshots[0]
|
||||||
|
self.logger.debug("[%s] Reusing snap \"%s\"", vdi_name, session.xenapi.VM.get_name_description(snapshot))
|
||||||
|
vm = snapshot # vm = session.xenapi.VM.get_by_name_label("tisbackup-%s"%(vdi_name))[0]
|
||||||
|
else:
|
||||||
|
self.logger.debug("[%s] Deleting %s old snaps", vdi_name, len(old_snapshots))
|
||||||
|
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:
|
try:
|
||||||
for vbd in session.xenapi.VM.get_VBDs(old_snapshot):
|
snapshot = session.xenapi.VM.snapshot(vm,"tisbackup-%s"%(vdi_name))
|
||||||
if session.xenapi.VBD.get_type(vbd) == 'CD' and session.xenapi.VBD.get_record(vbd)['empty'] == False:
|
self.logger.debug("[%s] got snapshot %s", vdi_name, snapshot)
|
||||||
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:
|
except XenAPI.Failure, error:
|
||||||
return("error when destroy snapshot %s"%(error))
|
return("error when snapshot %s"%(error))
|
||||||
|
#get snapshot opaqueRef
|
||||||
now = datetime.datetime.now()
|
vm = session.xenapi.VM.get_by_name_label("tisbackup-%s"%(vdi_name))[0]
|
||||||
self.logger.debug("[%s] Snapshot in progress",vdi_name)
|
session.xenapi.VM.set_name_description(snapshot,"snapshot created by tisbackup on: %s"%(now.strftime("%Y-%m-%d %H:%M")))
|
||||||
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:
|
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":
|
||||||
@ -190,7 +198,7 @@ class backup_xva(backup_generic):
|
|||||||
|
|
||||||
options = []
|
options = []
|
||||||
options_params = " ".join(options)
|
options_params = " ".join(options)
|
||||||
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)
|
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, reuse_snapshot=self.reuse_snapshot)
|
||||||
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
|
||||||
|
@ -40,11 +40,11 @@ class copy_vm_xcp(backup_generic):
|
|||||||
type = 'copy-vm-xcp'
|
type = 'copy-vm-xcp'
|
||||||
|
|
||||||
required_params = backup_generic.required_params + ['server_name','storage_name','password_file','vm_name','network_name']
|
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']
|
optional_params = backup_generic.optional_params + ['start_vm','max_copies', 'delete_snapshot']
|
||||||
|
|
||||||
start_vm = "no"
|
start_vm = "no"
|
||||||
max_copies = 1
|
max_copies = 1
|
||||||
|
delete_snapshot = "yes"
|
||||||
|
|
||||||
def read_config(self,iniconf):
|
def read_config(self,iniconf):
|
||||||
assert(isinstance(iniconf,ConfigParser))
|
assert(isinstance(iniconf,ConfigParser))
|
||||||
@ -53,9 +53,11 @@ class copy_vm_xcp(backup_generic):
|
|||||||
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'):
|
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):
|
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')
|
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:
|
||||||
@ -209,6 +211,10 @@ class copy_vm_xcp(backup_generic):
|
|||||||
if not 'NULL' in vdi:
|
if not 'NULL' in vdi:
|
||||||
size_backup = size_backup + int(session.xenapi.VDI.get_record(vdi)['physical_utilisation'])
|
size_backup = size_backup + int(session.xenapi.VDI.get_record(vdi)['physical_utilisation'])
|
||||||
|
|
||||||
|
result = (0,size_backup)
|
||||||
|
if self.delete_snapshot == 'no':
|
||||||
|
return result
|
||||||
|
|
||||||
#delete the snapshot
|
#delete the snapshot
|
||||||
try:
|
try:
|
||||||
for vbd in session.xenapi.VM.get_VBDs(snapshot):
|
for vbd in session.xenapi.VM.get_VBDs(snapshot):
|
||||||
@ -223,14 +229,13 @@ class copy_vm_xcp(backup_generic):
|
|||||||
result = (1,"error when destroy snapshot %s"%(error))
|
result = (1,"error when destroy snapshot %s"%(error))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
result = (0,size_backup)
|
|
||||||
return result
|
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, delete_snapshot=self.delete_snapshot)
|
||||||
|
|
||||||
if cmd[0] == 0:
|
if cmd[0] == 0:
|
||||||
timeExec = int(time.time()) - timestamp
|
timeExec = int(time.time()) - timestamp
|
||||||
@ -249,4 +254,4 @@ class copy_vm_xcp(backup_generic):
|
|||||||
stats['log']=str(e)
|
stats['log']=str(e)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
register_driver(copy_vm_xcp)
|
register_driver(copy_vm_xcp)
|
||||||
|
Loading…
Reference in New Issue
Block a user