Merge pull request 'simple-repo' (#1) from simple-repo into master

Reviewed-on: #1
This commit is contained in:
Jakobus Schürz 2023-06-04 01:00:56 +02:00
commit 8f3e40f190

View file

@ -32,8 +32,13 @@ except:
import dbus import dbus
import dbus.service import dbus.service
import dbus.glib # deprecated
from mkbackup.system_notification_emitter import Emitter #import dbus.glib
# replaces by this 2 lines
from dbus.mainloop.glib import DBusGMainLoop
DBusGMainLoop(set_as_default=True)
from mkbackup.system_notification_emitter import Emitter
from mkbackup.mkbackup_emitter import Emitter as EM from mkbackup.mkbackup_emitter import Emitter as EM
#from mksnapshotconfig import Config #from mksnapshotconfig import Config
@ -43,6 +48,10 @@ from mkbackup.mkbackup_btrfs_config import __version__ as confversion
__author__ = "Jakobus Schürz <jakob@schuerz.at>" __author__ = "Jakobus Schürz <jakob@schuerz.at>"
__version__ = "1.01.0" __version__ = "1.01.0"
class EmDBUSDesktop(EM):
def __init__(self):
super().__init__(conn=dbus.SystemBus(), object_path='/at/xundeenergie/notifications/advanced')
class Notification(Emitter): class Notification(Emitter):
def __init__(self): def __init__(self):
super().__init__(conn=dbus.SystemBus(), object_path='/at/xundeenergie/notifications/advanced/Notification') super().__init__(conn=dbus.SystemBus(), object_path='/at/xundeenergie/notifications/advanced/Notification')
@ -79,7 +88,7 @@ class progress_timer:
def initialize(self): def initialize(self):
#initialize timer #initialize timer
widgets = [self.description, pb.Percentage(), ' ', widgets = [self.description, pb.Percentage(), ' ',
pb.Bar(marker=pb.RotatingMarker()), ' ', pb.ETA()] pb.Bar(marker=pb.RotatingMarker()), ' ', pb.ETA()]
self.timer = pb.ProgressBar(widgets=widgets, maxval=self.n_iter).start() self.timer = pb.ProgressBar(widgets=widgets, maxval=self.n_iter).start()
@ -109,7 +118,7 @@ else:
def DEBUG(*msg,level=0,verbose=0): def DEBUG(*msg,level=0,verbose=0):
if verbose < level : if verbose < level :
return return
else: else:
#print(' '.join(msg)) #print(' '.join(msg))
for i in msg: print(i) for i in msg: print(i)
return return
@ -272,10 +281,10 @@ class BtrfsListing:
for pre, fill, node in RenderTree(wood if snap == None else vars()[stroot]): for pre, fill, node in RenderTree(wood if snap == None else vars()[stroot]):
print("%s%s" % (pre, node.name)) print("%s%s" % (pre, node.name))
else: else:
print("""anytree is not available. Please ask your sysadmin to install anytree with print("""anytree is not available. Please ask your sysadmin to install anytree with
pip3 install anytree""") pip3 install anytree""")
def list_sisters(self,ID,rev=False,older=None,younger=None,names=True): def list_sisters(self,ID,rev=False,older=None,younger=None,names=True):
result = [] result = []
if older == None: older = self.args.older if older == None: older = self.args.older
@ -334,7 +343,7 @@ class BtrfsListing:
def list_subvolumes(self,id,rev=False,names=True,incl_self=True): def list_subvolumes(self,id,rev=False,names=True,incl_self=True):
result= [] result= []
first = '' if names else id first = '' if names else id
if incl_self: result.append(first) if incl_self: result.append(first)
for sub in self._lssub(id): for sub in self._lssub(id):
result.append(self.svols[sub]['path'].partition(self.svols[id]['path']+'/')[2]) if names else result.append(sub) result.append(self.svols[sub]['path'].partition(self.svols[id]['path']+'/')[2]) if names else result.append(sub)
@ -360,7 +369,7 @@ class BtrfsListing:
result.append(self.svols[sub]['path']) if names else result.append(sub) result.append(self.svols[sub]['path']) if names else result.append(sub)
return(self._ret(result,reverse=rev)) return(self._ret(result,reverse=rev))
def _isbtrfs(self,path,store='SRC',tag='DEFAULT'): def _isbtrfs(self,path,store='SRC',tag='DEFAULT'):
mi = MountInfo(conn=self.args.config.getssh(tag,store)) mi = MountInfo(conn=self.args.config.getssh(tag,store))
logger.info("Filesysem for »%s« is %s" % (path,mi.fstype(path))) logger.info("Filesysem for »%s« is %s" % (path,mi.fstype(path)))
@ -421,14 +430,14 @@ class SubVolumeInfo(BtrfsListing):
for line in output.splitlines(): for line in output.splitlines():
#argmnts = [arg.strip() for arg in str(line, encoding='utf8').split(': ')] #argmnts = [arg.strip() for arg in str(line, encoding='utf8').split(': ')]
argmnts = [arg.strip() for arg in line.replace('\t',' ').split(': ')] argmnts = [arg.strip() for arg in line.replace('\t',' ').split(': ')]
if len(argmnts) > 1: if len(argmnts) > 1:
#setattr(self, self.tr_att(argmnts[0].strip()), argmnts[1].strip()) #setattr(self, self.tr_att(argmnts[0].strip()), argmnts[1].strip())
setattr(self, self.tr_att(argmnts[0]), argmnts[1]) setattr(self, self.tr_att(argmnts[0]), argmnts[1])
elif sv: elif sv:
snaps.append(argmnts[0].strip()) snaps.append(argmnts[0].strip())
else: else:
if argmnts[0].strip() == 'Snapshot(s):': if argmnts[0].strip() == 'Snapshot(s):':
sv = True sv = True
else: else:
self.path=argmnts[0].strip() self.path=argmnts[0].strip()
@ -450,7 +459,7 @@ class SubVolume(SubVolumeInfo):
self.exist = True self.exist = True
self.args = args self.args = args
self.timestamp = args.timestamp self.timestamp = args.timestamp
self.verbose = args.verbose self.verbose = args.verbose
self.tag = args.tag self.tag = args.tag
self.config = args.config #Config() self.config = args.config #Config()
@ -463,7 +472,7 @@ class SubVolume(SubVolumeInfo):
self.trans_ts = name.split('.')[1] self.trans_ts = name.split('.')[1]
self.trans_tag = name.split('.')[2] self.trans_tag = name.split('.')[2]
regexpart = re.compile('\.part') regexpart = re.compile('\.part')
self.OrigName = re.sub('\.part$','',self.SourceName) self.OrigName = re.sub('\.part$','',self.SourceName)
self.OrigLock = self.OrigName+'.part' self.OrigLock = self.OrigName+'.part'
@ -494,16 +503,16 @@ class SubVolume(SubVolumeInfo):
self.subvolumes = [] self.subvolumes = []
self.stderr = args.stderr self.stderr = args.stderr
self.DEBUG('[II] <%s> is %s: ' % (self.store, self.config.getStorePath(self.store,self.args.tag,original=True)),level=2) self.DEBUG('[II] <%s> is %s: ' % (self.store, self.config.getStorePath(self.store,self.args.tag,original=True)),level=2)
#self.partstep = (100 / (self.args.mdbpart * self.args.mdbsteps)) / len(self.list_subvolumes(self.id)) #self.partstep = (100 / (self.args.mdbpart * self.args.mdbsteps)) / len(self.list_subvolumes(self.id))
self.partstep = mdbslice / len(self.list_subvolumes(self.id)) self.partstep = mdbslice / len(self.list_subvolumes(self.id))
logger.debug("""Steps logger.debug("""Steps
mdpart: %i mdpart: %i
count subvolumes: %i count subvolumes: %i
len list_subvolumes: %i len list_subvolumes: %i
mdparts (mdbpart * mdbsteps): %i mdparts (mdbpart * mdbsteps): %i
pparts: %i pparts: %i
partstep: %f""" % (self.args.mdbpart, partstep: %f""" % (self.args.mdbpart,
self.count_subvolumes(self.id), self.count_subvolumes(self.id),
len(self.list_subvolumes(self.id)), len(self.list_subvolumes(self.id)),
self.args.mdbpart * self.args.mdbsteps, self.args.mdbpart * self.args.mdbsteps,
100, 100,
@ -535,8 +544,8 @@ class SubVolume(SubVolumeInfo):
Myos(dry=self.args.dry_run).remove(path+lf,args.config.getssh(self.tag,self.store)) Myos(dry=self.args.dry_run).remove(path+lf,args.config.getssh(self.tag,self.store))
except OSError as e: except OSError as e:
if e.errno == errno.EEXIST or errno.ENOENT: if e.errno == errno.EEXIST or errno.ENOENT:
pass pass
# if lockfile doesn't exist, continue # if lockfile doesn't exist, continue
#self.DEBUG('INFO - lockfile is not existing: <%s - %s>/%s' % (self.store,self.StorePath,path+lf),level=2) #self.DEBUG('INFO - lockfile is not existing: <%s - %s>/%s' % (self.store,self.StorePath,path+lf),level=2)
else: else:
raise e raise e
@ -564,7 +573,7 @@ class SubVolume(SubVolumeInfo):
st = self.store if store == None else store st = self.store if store == None else store
StorePath = self.config.getStorePath(st,self.args.tag) StorePath = self.config.getStorePath(st,self.args.tag)
if not issubvol(self.args,StorePath,store,self.args.tag): if not issubvol(self.args,StorePath,store,self.args.tag):
self.DEBUG("Failed to rename »<%s>%s«, is no btrfs-subvolume, or not existing" % (st,From),level=3) self.DEBUG("Failed to rename »<%s>%s«, is no btrfs-subvolume, or not existing" % (st,From),level=3)
return return
@ -582,8 +591,8 @@ class SubVolume(SubVolumeInfo):
return return
else: else:
if issubvol(self.args,StorePath+'/'+From,store,self.args.tag): if issubvol(self.args,StorePath+'/'+From,store,self.args.tag):
self.DEBUG(' =%s-rename> »<%s>/%s« --> %s' % (Action,st,From,To), level=1) self.DEBUG(' =%s-rename> »<%s>/%s« --> %s' % (Action,st,From,To), level=1)
else: else:
return return
try: try:
#print('DRY',self.args.dry_run) #print('DRY',self.args.dry_run)
@ -594,7 +603,7 @@ class SubVolume(SubVolumeInfo):
print(e) print(e)
except: except:
raise raise
return return
def lock(self,store=None): def lock(self,store=None):
@ -632,7 +641,7 @@ class SubVolume(SubVolumeInfo):
raise raise
self.scanfs() self.scanfs()
return return
def unlock(self,checked=False,store=None): def unlock(self,checked=False,store=None):
store = self.store store = self.store
self.DEBUG('try to unlock on action %s' % (self.args.action),level=4) self.DEBUG('try to unlock on action %s' % (self.args.action),level=4)
@ -699,7 +708,7 @@ class SubVolume(SubVolumeInfo):
def setprop(self,ro=True): def setprop(self,ro=True):
if self.args.action == 'create': if self.args.action == 'create':
sname = self.SnapLock sname = self.SnapLock
elif self.args.action == 'setprop': elif self.args.action == 'setprop':
sname = self.OrigName sname = self.OrigName
else: else:
sname = self.OrigLock sname = self.OrigLock
@ -719,10 +728,10 @@ class SubVolume(SubVolumeInfo):
self.args.config.remotecommand(tag=self.args.tag, store=self.store, cmd=cmd) self.args.config.remotecommand(tag=self.args.tag, store=self.store, cmd=cmd)
except: except:
self.DEBUG('setprop error',level=1) self.DEBUG('setprop error',level=1)
else: else:
pass pass
def create(self): def create(self):
self.DEBUG(' =create-snapshot=> from »<%s>/%s«' % (self.store, self.SourceName),level=1) self.DEBUG(' =create-snapshot=> from »<%s>/%s«' % (self.store, self.SourceName),level=1)
#compile regular expression for ignoring subvolume-names #compile regular expression for ignoring subvolume-names
@ -785,7 +794,7 @@ class SubVolume(SubVolumeInfo):
self.SnapID = self.svols[i]['id'] self.SnapID = self.svols[i]['id']
BtrfsListing.CreatedSubvolumes.push((self.store,self.SnapName)) BtrfsListing.CreatedSubvolumes.push((self.store,self.SnapName))
return(list([self.svols[i]['id'],self.svols[i]['path']])) return(list([self.svols[i]['id'],self.svols[i]['path']]))
raise CreateError('FAILURE - create new snapshot failed %s' % (self.SnapLock), 0) raise CreateError('FAILURE - create new snapshot failed %s' % (self.SnapLock), 0)
except: except:
raise CreateError raise CreateError
@ -806,7 +815,7 @@ class SubVolume(SubVolumeInfo):
sname = self.OrigLock sname = self.OrigLock
sid = self.id sid = self.id
#get uuids of SNP/SRC and BKP and compare. If they are the same, no transfer, if they are different, make transfer to external media #get uuids of SNP/SRC and BKP and compare. If they are the same, no transfer, if they are different, make transfer to external media
#print(self.config.getDevice(store='BKP')) #print(self.config.getDevice(store='BKP'))
try: try:
@ -834,7 +843,7 @@ class SubVolume(SubVolumeInfo):
logger.critical(" |no-transfer: Filesystem for »%s« not mounted: »%s«" % ('BKP',self.config.getMountPath(store='BKP',tag=args.tag))) logger.critical(" |no-transfer: Filesystem for »%s« not mounted: »%s«" % ('BKP',self.config.getMountPath(store='BKP',tag=args.tag)))
return return
if uuidS == uuidB: if uuidS == uuidB:
# Same Filesystem on SRC/SNP and BKP. No transfer # Same Filesystem on SRC/SNP and BKP. No transfer
logger.critical(" |no-transfer: external backupmedia obviously not mounted") logger.critical(" |no-transfer: external backupmedia obviously not mounted")
return return
@ -854,7 +863,7 @@ class SubVolume(SubVolumeInfo):
# try: # try:
# print("%s exists; is directory" % (self.BkpPath)) # print("%s exists; is directory" % (self.BkpPath))
# print("%s -> change to subvolume, this may take a while" % (self.BkpPath)) # print("%s -> change to subvolume, this may take a while" % (self.BkpPath))
# # rename original BKPStore # # rename original BKPStore
# print('A ren') # print('A ren')
# cmd = ['mv',self.BkpPath,self.BkpPath+'.orig'] # cmd = ['mv',self.BkpPath,self.BkpPath+'.orig']
# sp_call(self.args,cmd) # sp_call(self.args,cmd)
@ -910,7 +919,7 @@ class SubVolume(SubVolumeInfo):
if BKP.svols[bsub]['ruuid'] == self.svols[sis]['uuid']: if BKP.svols[bsub]['ruuid'] == self.svols[sis]['uuid']:
plist[self.svols[sis]['id']] = self.svols[sis]['id'] plist[self.svols[sis]['id']] = self.svols[sis]['id']
transfers[self.svols[sub]['path']] = dict() transfers[self.svols[sub]['path']] = dict()
if len(plist) > 0: if len(plist) > 0:
v=[int(i) for i in plist.values()] v=[int(i) for i in plist.values()]
@ -1017,7 +1026,7 @@ class SubVolume(SubVolumeInfo):
#output = args.config.remotecommand(tag=args.tag, store=store, cmd=cmd) #output = args.config.remotecommand(tag=args.tag, store=store, cmd=cmd)
if not self.args.transferinfo: if not self.args.transferinfo:
# print("S->R",first,second) # print("S->R",first,second)
# stdin_send,stdout_send,stderr_send = cmdsh(self.tag,self.store,first) # stdin_send,stdout_send,stderr_send = cmdsh(self.tag,self.store,first)
@ -1054,7 +1063,7 @@ class SubVolume(SubVolumeInfo):
# self.DEBUG("[II] TARGET => LINKNAME: %s => %s" % (target.strip(),link_name.strip()),level=3) # self.DEBUG("[II] TARGET => LINKNAME: %s => %s" % (target.strip(),link_name.strip()),level=3)
# else: # else:
# raise e # raise e
def symlink(self): def symlink(self):
for st in list(self.args.sourcepath.keys())[0], list(self.args.destpath.keys())[0]: for st in list(self.args.sourcepath.keys())[0], list(self.args.destpath.keys())[0]:
StorePath = self.config.getStorePath(st,self.args.tag) StorePath = self.config.getStorePath(st,self.args.tag)
@ -1062,7 +1071,7 @@ class SubVolume(SubVolumeInfo):
linkName = self.basename+'.'+args.config.getSymLink(args.tag) linkName = self.basename+'.'+args.config.getSymLink(args.tag)
self.DEBUG('%-12s =>»<%s>/%s«' % (' =symlink>',st,linkName),level=0) self.DEBUG('%-12s =>»<%s>/%s«' % (' =symlink>',st,linkName),level=0)
self.symlink_force('./'+self.SnapName, StorePath+'/'+linkName,st) self.symlink_force('./'+self.SnapName, StorePath+'/'+linkName,st)
if args.config.getSymLink(args.tag) != args.config.getSymLink(): if args.config.getSymLink(args.tag) != args.config.getSymLink():
self.DEBUG('%-12s =>»<%s>/%s«' % (' =symlink>',st,self.basename+'.LAST'),level=0) self.DEBUG('%-12s =>»<%s>/%s«' % (' =symlink>',st,self.basename+'.LAST'),level=0)
self.symlink_force('./'+self.SnapName, StorePath+'/'+self.basename+'.LAST',st) self.symlink_force('./'+self.SnapName, StorePath+'/'+self.basename+'.LAST',st)
@ -1074,7 +1083,7 @@ class SubVolume(SubVolumeInfo):
linkName = self.basename linkName = self.basename
self.DEBUG('%-12s =>»<%s>/%s«' % (' =symlink>',st,linkName),level=0) self.DEBUG('%-12s =>»<%s>/%s«' % (' =symlink>',st,linkName),level=0)
self.symlink_force('./'+self.SnapName, StorePath+'/'+linkName,st) self.symlink_force('./'+self.SnapName, StorePath+'/'+linkName,st)
# if args.config.getSymLink(args.tag) != args.config.getSymLink(): # if args.config.getSymLink(args.tag) != args.config.getSymLink():
# self.DEBUG('%-12s =>»<%s>/%s«' % (' =symlink>',st,self.basename+'.LAST'),level=0) # self.DEBUG('%-12s =>»<%s>/%s«' % (' =symlink>',st,self.basename+'.LAST'),level=0)
# self.symlink_force('./'+self.SnapName, StorePath+'/'+self.basename+'.LAST',st) # self.symlink_force('./'+self.SnapName, StorePath+'/'+self.basename+'.LAST',st)
@ -1088,7 +1097,7 @@ class SubVolume(SubVolumeInfo):
sname = self.OrigLock sname = self.OrigLock
slock = self.OLockFile slock = self.OLockFile
sid = self.id sid = self.id
#print('delete %s - %s with %s and action %s' % (sname,sid,slock,self.args.action)) #print('delete %s - %s with %s and action %s' % (sname,sid,slock,self.args.action))
@ -1141,10 +1150,10 @@ class SubVolume(SubVolumeInfo):
if self.args.npb: pt.update() if self.args.npb: pt.update()
if self.args.npb: pt.finish() if self.args.npb: pt.finish()
def main(self): def main(self):
#print(self.svols) #print(self.svols)
#print(self.list_sisters(self.ID)) #print(self.list_sisters(self.ID))
#try: #try:
self.parse_btrfs_show() self.parse_btrfs_show()
@ -1164,7 +1173,7 @@ def main(args):
#L.main() #L.main()
#L.list_sisters() #L.list_sisters()
#X=SubVolume(BtrfsListing) #X=SubVolume(BtrfsListing)
def issubvol(args,path,store='SRC',tag=None): def issubvol(args,path,store='SRC',tag=None):
#print("issubvol-store",store,tag,path) #print("issubvol-store",store,tag,path)
if not path == None: if not path == None:
@ -1174,17 +1183,17 @@ def issubvol(args,path,store='SRC',tag=None):
except: except:
return False return False
return True if int(output) == 256 else False return True if int(output) == 256 else False
def cleanup(args): def cleanup(args):
args.mdbsteps = 4 #create, setprop, transfer, cleanup args.mdbsteps = 4 #create, setprop, transfer, cleanup
args.mdbslice = 100 / 4 args.mdbslice = 100 / 4
DEBUG(' --== cleanup ==-->',verbose=args.verbose,level=1) DEBUG(' --== cleanup ==-->',verbose=args.verbose,level=1)
#self.partstep = (100 / (args.mdbpart * args.mdbsteps)) / len(self.list_subvolumes(self.id)) #self.partstep = (100 / (args.mdbpart * args.mdbsteps)) / len(self.list_subvolumes(self.id))
if args.npb: pt = progress_timer(description= ' --== cleanup ==-->', n_iter=6) if args.npb: pt = progress_timer(description= ' --== cleanup ==-->', n_iter=6)
args.action = 'cleanup' args.action = 'cleanup'
#DEL = dict() #DEL = dict()
DEL = Stack() DEL = Stack()
ST = dict() ST = dict()
explock = re.compile('.*.~lock$') explock = re.compile('.*.~lock$')
@ -1227,7 +1236,7 @@ def cleanup(args):
DEBUG(args,' --cleanup *.part$-Snapshots',level=3) DEBUG(args,' --cleanup *.part$-Snapshots',level=3)
for i in ST[st].svols: for i in ST[st].svols:
subvol = ST[st].svols[i]['path'] subvol = ST[st].svols[i]['path']
if exppart.search(subvol): if exppart.search(subvol):
DEL.push([st,subvol]) DEL.push([st,subvol])
# Delete them # Delete them
@ -1273,7 +1282,7 @@ def create(args):
SRC[snap].unlock() SRC[snap].unlock()
SRC[snap].symlink() SRC[snap].symlink()
except RuntimeError as e: except RuntimeError as e:
if e.args[1] == 0: if e.args[1] == 0:
print('nicht so schlimm') print('nicht so schlimm')
else: else:
raise e raise e
@ -1300,7 +1309,7 @@ def rollback(args):
SRC[snap].symlink_sysvol() SRC[snap].symlink_sysvol()
#SRC[snap].rename() #SRC[snap].rename()
except RuntimeError as e: except RuntimeError as e:
if e.args[1] == 0: if e.args[1] == 0:
print('nicht so schlimm') print('nicht so schlimm')
else: else:
raise e raise e
@ -1324,7 +1333,7 @@ def delete(args):
SRC[snap].setprop(ro=False) SRC[snap].setprop(ro=False)
SRC[snap].delete() SRC[snap].delete()
except RuntimeError as e: except RuntimeError as e:
if e.args[1] == 0: if e.args[1] == 0:
print("delete error - nicht so schlimm") print("delete error - nicht so schlimm")
else: else:
raise e raise e
@ -1334,7 +1343,7 @@ def delete(args):
except: except:
raise raise
return return
def setprop(args): def setprop(args):
args.mdbsteps = 4 #create, setprop, transfer, cleanup args.mdbsteps = 4 #create, setprop, transfer, cleanup
args.mdbslice = 100 / 4 args.mdbslice = 100 / 4
@ -1348,7 +1357,7 @@ def setprop(args):
SRC[snap].unlock() SRC[snap].unlock()
except RuntimeError as e: except RuntimeError as e:
print(e.args,e.args[1]) print(e.args,e.args[1])
if e.args[1] == 0: if e.args[1] == 0:
print("setprop error - nicht so schlimm") print("setprop error - nicht so schlimm")
else: else:
raise e raise e
@ -1358,7 +1367,7 @@ def setprop(args):
except: except:
raise raise
return return
def lists(args): def lists(args):
args.mdbsteps = 4 #create, setprop, transfer, cleanup args.mdbsteps = 4 #create, setprop, transfer, cleanup
args.mdbslice = 100 / 4 args.mdbslice = 100 / 4
@ -1383,7 +1392,7 @@ def lists(args):
if args.print_config: if args.print_config:
args.config.PrintConfig(tag = None if args.tagset else args.tag, of=args.of) args.config.PrintConfig(tag = None if args.tagset else args.tag, of=args.of)
if args.showyoungest: if args.showyoungest:
ST=dict() ST=dict()
for st in args.store: for st in args.store:
@ -1398,7 +1407,7 @@ def lists(args):
dirlist = dict() dirlist = dict()
for snps in glob.glob(args.config.getStorePath(st,args.tag)+'/'+vol+'.*'): for snps in glob.glob(args.config.getStorePath(st,args.tag)+'/'+vol+'.*'):
#print("snps",snps) #print("snps",snps)
if len(os.path.basename(snps).split('.')) == 3: if len(os.path.basename(snps).split('.')) == 3:
if not os.path.basename(snps).split('.')[1] in dirlist: if not os.path.basename(snps).split('.')[1] in dirlist:
dirlist[os.path.basename(snps).split('.')[1]] = list() dirlist[os.path.basename(snps).split('.')[1]] = list()
dirlist[os.path.basename(snps).split('.')[1]].append(os.path.basename(snps)) dirlist[os.path.basename(snps).split('.')[1]].append(os.path.basename(snps))
@ -1406,7 +1415,7 @@ def lists(args):
for snp in dirlist[t]: for snp in dirlist[t]:
#print("T",dirlist[t],snp) #print("T",dirlist[t],snp)
for intv in ST[st][vol].keys(): for intv in ST[st][vol].keys():
R = re.compile(intv +'$') R = re.compile(intv +'$')
#print("I",intv) #print("I",intv)
if R.search(snp): if R.search(snp):
#print("snp",st,vol,intv,snp) #print("snp",st,vol,intv,snp)
@ -1448,14 +1457,14 @@ def lists(args):
s['dirlist'] = ST[st][vol]['dirlist'][sorted(dirlist.keys()).pop()] s['dirlist'] = ST[st][vol]['dirlist'][sorted(dirlist.keys()).pop()]
else: else:
#print("C",i) #print("C",i)
#if i.split('.')[2] == args.tag: #if i.split('.')[2] == args.tag:
#print("D",i) #print("D",i)
#s[i.split('.')[1]] = i #s[i.split('.')[1]] = i
if intv == args.tag: if intv == args.tag:
s[k] = i s[k] = i
else: else:
missing.append(intv) missing.append(intv)
lo = 0 lo = 0
for i in reversed(sorted(s.keys())): for i in reversed(sorted(s.keys())):
#for j in s[i] if i == 'dirlist' else [s[i]]: #for j in s[i] if i == 'dirlist' else [s[i]]:
@ -1481,18 +1490,18 @@ def lists(args):
res = subprocess.Popen(cmd,stdout=subprocess.PIPE, stderr=args.stderr) res = subprocess.Popen(cmd,stdout=subprocess.PIPE, stderr=args.stderr)
output,error = res.communicate() output,error = res.communicate()
if res.returncode > 0: if res.returncode > 0:
raise raise
except: except:
raise raise
#if output[0] == 0: #if output[0] == 0:
cut = 120 cut = 120
for line in output.splitlines(): for line in output.splitlines():
l = line.decode() l = line.decode()
if "ACTIVATES" in l: if "ACTIVATES" in l:
cut = l.find("ACTIVATES") cut = l.find("ACTIVATES")
i = l.find("UNIT") i = l.find("UNIT")
print(l[:cut]) print(l[:cut])
elif reintv.search(l): elif reintv.search(l):
l = l[:cut] l = l[:cut]
o = l.replace("timer-","").replace(".timer","").rstrip() o = l.replace("timer-","").replace(".timer","").rstrip()
x = o[i:].rstrip(), x = o[i:].rstrip(),
@ -1553,7 +1562,7 @@ def lists(args):
for i in SRC[snap].list_subvolumes(SRC[snap].id,rev=args.reverse): print(fp+i) for i in SRC[snap].list_subvolumes(SRC[snap].id,rev=args.reverse): print(fp+i)
except RuntimeError as e: except RuntimeError as e:
print(e.args,e.args[1]) print(e.args,e.args[1])
if e.args[1] == 0: if e.args[1] == 0:
print("list error - nicht so schlimm") print("list error - nicht so schlimm")
else: else:
raise e raise e
@ -1596,7 +1605,7 @@ def restore(args):
#print('RESTORE FILES', args) #print('RESTORE FILES', args)
# if User running "mkbackup restore" is root, set uroot=True # if User running "mkbackup restore" is root, set uroot=True
if os.getuid() == 0: if os.getuid() == 0:
uroot = True uroot = True
else: else:
uroot = False uroot = False
@ -1663,23 +1672,22 @@ def restore(args):
else: raise else: raise
#shutil.copy(src,dest) #shutil.copy(src,dest)
mounts.close() mounts.close()
#class desktop_notification: #class desktop_notification:
# def __init__(self, args, urgency=1): # def __init__(self, args, urgency=1):
# self.args = args # self.args = args
# self.dbus_path = "/at/xundeenergie/notifications" # self.dbus_path = "/at/xundeenergie/notifications/advanced"
# self.dbus_iface = "at.xundeenergie.notifications.advanced" # self.dbus_iface = "at.xundeenergie.Notification"
# self.dbus_busname = "at.xundeenergie.notifications"
# self.timestamp = datetime.datetime.now() # self.timestamp = datetime.datetime.now()
# self.time = self.timestamp.strftime('%H:%M:%S') # self.time = self.timestamp.strftime('%H:%M:%S')
# self.date = self.timestamp.strftime('%d. %B %Y') # self.date = self.timestamp.strftime('%d. %B %Y')
# self.bus = dbus.SystemBus() # self.bus = dbus.SystemBus()
# if int(urgency) == 0: # if int(urgency) == 0:
# self.signal_name = 'Notification_low' # self.signal_name = 'low'
# elif int(urgency) == 1: # elif int(urgency) == 1:
# self.signal_name = 'Notification_normal' # self.signal_name = 'normal'
# else: # else:
# self.signal_name = 'Notification_critical' # self.signal_name = 'critical'
# print('NO',int(urgency),self.signal_name) # print('NO',int(urgency),self.signal_name)
# #
# def send_signal(self, intv='default', *args): # def send_signal(self, intv='default', *args):
@ -1687,15 +1695,16 @@ def restore(args):
# msg = dict() # msg = dict()
# msg['sender'] = "mkbackup" # msg['sender'] = "mkbackup"
# msg['msgheader'] = "%s-backup" % (self.args.tag) # msg['msgheader'] = "%s-backup" % (self.args.tag)
# msg['msgbody'] = """am %s # msg['msgbody'] = """am %s
#um %s Uhr abgeschlossen. #um %s Uhr abgeschlossen.
# #
#%s #%s
#(Ugency: %s) #(Ugency: %s)
#""" % (self.date, self.time, '\n'.join(args), self.signal_name) #""" % (self.date, self.time, '\n'.join(args), self.signal_name)
# msg['expiration_timeout'] = '-1' # msg['expiration_timeout'] = '-1'
# message = dbus.lowlevel.SignalMessage(self.dbus_path, self.dbus_iface, self.signal_name) # message = dbus.lowlevel.SignalMessage(self.dbus_path, self.dbus_iface, self.signal_name)
# message.append(msg) # #message.append(msg)
# message.append({'body': 'blafoo'})
# self.bus.send_message(message) # self.bus.send_message(message)
# PARSER # PARSER
@ -1714,21 +1723,21 @@ parser.add_argument('-L', '--logfile', default=None, help='''Write output also t
parser.add_argument('-i', '--ignore', action='append', help='''Regular expression pattern for ignoring several subvolumes to be not backed up (and subvolumes unter them) parser.add_argument('-i', '--ignore', action='append', help='''Regular expression pattern for ignoring several subvolumes to be not backed up (and subvolumes unter them)
Use it more than once''') Use it more than once''')
parser.add_argument('-n', '--no-progressbar', dest='npb', action='store_false', default=True, help='''Dont show progressbar (for use in systemctl-unit for example)''') parser.add_argument('-n', '--no-progressbar', dest='npb', action='store_false', default=True, help='''Dont show progressbar (for use in systemctl-unit for example)''')
parser.add_argument('-B', '--backup-mount-path', parser.add_argument('-B', '--backup-mount-path',
dest='bkpmount', dest='bkpmount',
default=config.getMountPath('BKP'), default=config.getMountPath('BKP'),
help='''set path to destination mountpoint of backup-mountpoint. (default=%s) overrides 'BKP-Path':''' % (config.getMountPath('BKP'))) help='''set path to destination mountpoint of backup-mountpoint. (default=%s) overrides 'BKP-Path':''' % (config.getMountPath('BKP')))
parser.add_argument('-b', '--backup-store', parser.add_argument('-b', '--backup-store',
dest='bkpstore', dest='bkpstore',
default=config.getStoreName('BKP'), default=config.getStoreName('BKP'),
help='''set storename in backup-mount. (default=%s) overrides 'BKP-Store':''' % (config.getStoreName('BKP'))) help='''set storename in backup-mount. (default=%s) overrides 'BKP-Store':''' % (config.getStoreName('BKP')))
parser.add_argument('-S', '--snapshot-mount-path', parser.add_argument('-S', '--snapshot-mount-path',
dest='snpmount', dest='snpmount',
default=config.getMountPath('SNP'), default=config.getMountPath('SNP'),
help='''set path to destination mountpoint of snapshot-mountpoint. (default=%s) overrides 'SNP-Path':''' % (config.getMountPath('SNP'))) help='''set path to destination mountpoint of snapshot-mountpoint. (default=%s) overrides 'SNP-Path':''' % (config.getMountPath('SNP')))
parser.add_argument('-s', '--snapshot-store', parser.add_argument('-s', '--snapshot-store',
dest='snpstore', dest='snpstore',
default=config.getStoreName('SNP'), default=config.getStoreName('SNP'),
help='''set storename in snapshot-mount. (default=%s) overrides 'BKP-Store':''' % (config.getStoreName('SNP'))) help='''set storename in snapshot-mount. (default=%s) overrides 'BKP-Store':''' % (config.getStoreName('SNP')))
parser.add_argument('-N', '--notification', default=None, help='''Send notification. Possible values are "desktop" ''') parser.add_argument('-N', '--notification', default=None, help='''Send notification. Possible values are "desktop" ''')
parser.add_argument('-U', '--notification_urgency', default=None, help='''Send notification. Possible values are 0=low, 1=normal, 2=critical ''') parser.add_argument('-U', '--notification_urgency', default=None, help='''Send notification. Possible values are 0=low, 1=normal, 2=critical ''')
@ -1737,8 +1746,8 @@ parser.add_argument('-U', '--notification_urgency', default=None, help='''Send n
subparsers = parser.add_subparsers() subparsers = parser.add_subparsers()
list_parser=subparsers.add_parser('list') list_parser=subparsers.add_parser('list')
list_parser.add_argument("store", list_parser.add_argument("store",
default='SRC', default='SRC',
metavar='stores and snapshots', metavar='stores and snapshots',
nargs='*', nargs='*',
help="""one of SRC, BKP or SNP - where is the snapshot help="""one of SRC, BKP or SNP - where is the snapshot
@ -1767,8 +1776,8 @@ list_parser.set_defaults(func=lists)
list_parser.set_defaults(action='list') list_parser.set_defaults(action='list')
create_parser=subparsers.add_parser('create') create_parser=subparsers.add_parser('create')
create_parser.add_argument("store", create_parser.add_argument("store",
default='SRC', default='SRC',
metavar='stores and snapshots', metavar='stores and snapshots',
nargs='*', nargs='*',
help="""one of SRC or SNP - where is the snapshot located and one ore more snapshots help="""one of SRC or SNP - where is the snapshot located and one ore more snapshots
@ -1779,8 +1788,8 @@ create_parser.set_defaults(func=create)
create_parser.set_defaults(action='create') create_parser.set_defaults(action='create')
rollback_parser=subparsers.add_parser('rollback') rollback_parser=subparsers.add_parser('rollback')
rollback_parser.add_argument("store", rollback_parser.add_argument("store",
default='SRC', default='SRC',
metavar='stores and snapshots', metavar='stores and snapshots',
nargs='*', nargs='*',
help="""one of SRC, BKP or SNP - where is the snapshot help="""one of SRC, BKP or SNP - where is the snapshot
@ -1790,8 +1799,8 @@ rollback_parser.set_defaults(func=rollback)
rollback_parser.set_defaults(action='rollback') rollback_parser.set_defaults(action='rollback')
delete_parser=subparsers.add_parser('delete') delete_parser=subparsers.add_parser('delete')
delete_parser.add_argument("store", delete_parser.add_argument("store",
default='SRC', default='SRC',
metavar='stores and snapshots', metavar='stores and snapshots',
nargs='*', nargs='*',
help="""one of SRC, BKP or SNP - where is the snapshot help="""one of SRC, BKP or SNP - where is the snapshot
@ -1800,23 +1809,23 @@ delete_parser.set_defaults(func=delete)
delete_parser.set_defaults(action='delete') delete_parser.set_defaults(action='delete')
transfer_parser=subparsers.add_parser('transfer') transfer_parser=subparsers.add_parser('transfer')
transfer_parser.add_argument("snapshots", transfer_parser.add_argument("snapshots",
default='SRC', default='SRC',
nargs='*', nargs='*',
help="""one of SRC or SNP - where is the snapshot located and one ore more snapshots help="""one of SRC or SNP - where is the snapshot located and one ore more snapshots
which to be transfered to the external backup-device. which to be transfered to the external backup-device.
BKP is ignored!!!""") BKP is ignored!!!""")
transfer_parser.add_argument('--no-clones', action='store_true', default=False, help="""do not use clones for transfer, only parent (if present)""") transfer_parser.add_argument('--no-clones', action='store_true', default=False, help="""do not use clones for transfer, only parent (if present)""")
transfer_parser.add_argument('-i', '--info', transfer_parser.add_argument('-i', '--info',
dest='transferinfo', dest='transferinfo',
action='store_true', action='store_true',
default=False, default=False,
help="""show only if initial or incremental transfer is done and the parents""") help="""show only if initial or incremental transfer is done and the parents""")
transfer_parser.set_defaults(func=transfer) transfer_parser.set_defaults(func=transfer)
transfer_parser.set_defaults(action='transfer') transfer_parser.set_defaults(action='transfer')
cleanup_parser=subparsers.add_parser('cleanup') cleanup_parser=subparsers.add_parser('cleanup')
cleanup_parser.add_argument("snapshots", cleanup_parser.add_argument("snapshots",
nargs='*', nargs='*',
help='''cleanup all snapshots, which are older and more help='''cleanup all snapshots, which are older and more
than allowed in config''') than allowed in config''')
@ -1824,13 +1833,13 @@ cleanup_parser.set_defaults(func=cleanup)
cleanup_parser.set_defaults(action='cleanup') cleanup_parser.set_defaults(action='cleanup')
setprop_parser=subparsers.add_parser('setprop') setprop_parser=subparsers.add_parser('setprop')
setprop_parser.add_argument("store", setprop_parser.add_argument("store",
default='SRC', default='SRC',
metavar='stores and snapshots', metavar='stores and snapshots',
nargs='*', nargs='*',
help='''one of SRC, BKP or SNP - where is the snapshot help='''one of SRC, BKP or SNP - where is the snapshot
located and one ore more snapshots''') located and one ore more snapshots''')
setprop_parser.add_argument("-r", "--ro", setprop_parser.add_argument("-r", "--ro",
default=False, default=False,
action='store_true', action='store_true',
help='''setproperty to readonly. If -r is not given, help='''setproperty to readonly. If -r is not given,
@ -1839,10 +1848,10 @@ setprop_parser.set_defaults(func=setprop)
setprop_parser.set_defaults(action='setprop') setprop_parser.set_defaults(action='setprop')
restore_parser=subparsers.add_parser('restore') restore_parser=subparsers.add_parser('restore')
restore_parser.add_argument("file", restore_parser.add_argument("file",
nargs='*', nargs='*',
help="""restore all given files""") help="""restore all given files""")
restore_parser.add_argument("-n", "--no-preserve", restore_parser.add_argument("-n", "--no-preserve",
default=False, default=False,
action='store_true', action='store_true',
help="""if set, the original file will be overwritten. If not set, help="""if set, the original file will be overwritten. If not set,
@ -1862,7 +1871,7 @@ if __name__ == '__main__':
# args.notification['bool']=False # args.notification['bool']=False
# args.notification['type']=None # args.notification['type']=None
# --- Logger --- # --- Logger ---
levels = (logging.CRITICAL, logging.ERROR, logging.WARNING, logging.INFO, logging.DEBUG, logging.NOTSET) levels = (logging.CRITICAL, logging.ERROR, logging.WARNING, logging.INFO, logging.DEBUG, logging.NOTSET)
#print(logging.CRITICAL, logging.ERROR, logging.WARNING, logging.INFO, logging.DEBUG, logging.NOTSET) #print(logging.CRITICAL, logging.ERROR, logging.WARNING, logging.INFO, logging.DEBUG, logging.NOTSET)
print('verbose', args.verbose, levels[args.verbose]) print('verbose', args.verbose, levels[args.verbose])
@ -1895,12 +1904,12 @@ if __name__ == '__main__':
if not 'dry_run' in args: if not 'dry_run' in args:
args.dry_run=False args.dry_run=False
if 'store' in args: if 'store' in args:
if isstring(args.store): args.store = args.store.split(' ') if isstring(args.store): args.store = args.store.split(' ')
else: else:
args.store = [] args.store = []
if 'snapshots' in args: if 'snapshots' in args:
if isstring(args.snapshots): args.snapshots = args.snapshots.split() if isstring(args.snapshots): args.snapshots = args.snapshots.split()
else: else:
args.snapshots = [] args.snapshots = []
@ -1931,7 +1940,7 @@ if __name__ == '__main__':
# tag = None is not allowed. Set it to misc, if not set # tag = None is not allowed. Set it to misc, if not set
args.tagset = False args.tagset = False
if args.tag == None: if args.tag == None:
args.tag = 'misc' args.tag = 'misc'
args.tagset = True # if no tag was given, and tag is set here, this value is true - it indicates, tag was set automatically to 'misc' args.tagset = True # if no tag was given, and tag is set here, this value is true - it indicates, tag was set automatically to 'misc'
@ -1994,8 +2003,8 @@ Author: %s""" % (confversion,__version__,__author__))
args.stderr=None args.stderr=None
if args.verbose > 0: if args.verbose > 0:
args.npb = False args.npb = False
#DEBUG("Arguments",args,verbose=args.verbose) #DEBUG("Arguments",args,verbose=args.verbose)
if args.verbose > 3: if args.verbose > 3:
@ -2009,6 +2018,12 @@ Author: %s""" % (confversion,__version__,__author__))
args.mdb = EmDBUS() args.mdb = EmDBUS()
args.mdb.reset(args.tag) args.mdb.reset(args.tag)
args.mdb.start(args.tag) args.mdb.start(args.tag)
args.mdbd = EmDBUSDesktop()
# msg = dict()
# msg['sender'] = "mkbackup"
# msg['header'] = "%s-backup" % (args.tag)
# msg['body'] = "Start"
# args.mdbd.critical(msg)
################################################################# #################################################################
## Run action ## ## Run action ##
################################################################# #################################################################
@ -2053,9 +2068,9 @@ Author: %s""" % (confversion,__version__,__author__))
# for s in args.config.ssh[t].keys(): # for s in args.config.ssh[t].keys():
# if not args.config.ssh[t][s]['ssh'] == None: # if not args.config.ssh[t][s]['ssh'] == None:
# print("CLOSE",t,s) # print("CLOSE",t,s)
# args.config.ssh[t][s]['ssh'].close() # args.config.ssh[t][s]['ssh'].close()
# print summary over all actions # print summary over all actions
volumes = list() volumes = list()
if not args.action == 'list' and not args.action == 'restore': if not args.action == 'list' and not args.action == 'restore':
@ -2065,7 +2080,7 @@ snapshots: %s
""" % (args.store,args.snapshots)) """ % (args.store,args.snapshots))
DEBUG("Created Subvolumes:",level=0,verbose=args.verbose) DEBUG("Created Subvolumes:",level=0,verbose=args.verbose)
volumes.append('<b>Volumes created:</b>') volumes.append('<b>Volumes created:</b>')
if BtrfsListing.CreatedSubvolumes.is_empty(): if BtrfsListing.CreatedSubvolumes.is_empty():
volumes.append('---') volumes.append('---')
print('''--- print('''---
''') ''')
@ -2077,7 +2092,7 @@ snapshots: %s
DEBUG("Transfered Subvolumes:",level=0,verbose=args.verbose) DEBUG("Transfered Subvolumes:",level=0,verbose=args.verbose)
volumes.append('<b>Volumes transfered:</b>') volumes.append('<b>Volumes transfered:</b>')
if BtrfsListing.TransferedSubvolumes.is_empty(): if BtrfsListing.TransferedSubvolumes.is_empty():
volumes.append('---') volumes.append('---')
print('''--- print('''---
''') ''')
@ -2086,10 +2101,10 @@ snapshots: %s
volumes.append(i[1]) volumes.append(i[1])
print(i) print(i)
volumes.append('') volumes.append('')
DEBUG("Deleted Subvolumes:",level=0,verbose=args.verbose) DEBUG("Deleted Subvolumes:",level=0,verbose=args.verbose)
volumes.append('<b>Volumes deleted:</b>') volumes.append('<b>Volumes deleted:</b>')
if BtrfsListing.DeletedSubvolumes.is_empty(): if BtrfsListing.DeletedSubvolumes.is_empty():
volumes.append('---') volumes.append('---')
print(''' --- print(''' ---
''') ''')
@ -2101,49 +2116,48 @@ snapshots: %s
print(args.notification, config.getNotification(intv=args.tag), args.notification_urgency, config.getUrgency(intv=args.tag)) print(args.notification, config.getNotification(intv=args.tag), args.notification_urgency, config.getUrgency(intv=args.tag))
if args.notification == None: if args.notification == None:
args.notification = config.getNotification(intv=args.tag) args.notification = config.getNotification(intv=args.tag)
if args.notification_urgency == None: if args.notification_urgency == None:
args.notification_urgency = config.getUrgency(intv=args.tag) args.notification_urgency = config.getUrgency(intv=args.tag)
print(args.notification, args.notification_urgency) print(args.notification, args.notification_urgency)
if args.notification == 'desktop': if args.notification == 'desktop':
# notify = desktop_notification(args, urgency=args.notification_urgency) # notify = desktop_notification(args, urgency=args.notification_urgency)
# notify.send_signal(args, *volumes) # notify.send_signal(args, *volumes)
# print(volumes) # print(volumes)
# print(*volumes) # print(*volumes)
msg = dict() msg = dict()
msg['sender'] = "mkbackup" msg['sender'] = "mkbackup"
msg['header'] = "%s-backup" % (args.tag) msg['header'] = "%s-backup" % (args.tag)
msg['body'] = """am %s msg['body'] = """am %s
um %s Uhr abgeschlossen. um %s Uhr abgeschlossen.
%s %s
http://www.google.com
<a href="file:///home/jakob/backup">TEST</a>
(Ugency: normal) (Ugency: normal)
""" % (args.ts.strftime('%Y-%m-%d'), args.ts.strftime('%H:%M:%S'), '\r'.join(volumes)) """ % (args.ts.strftime('%Y-%m-%d'), args.ts.strftime('%H:%M:%S'), '\r'.join(volumes))
# msg['action'] = dict() # msg['action'] = dict()
# msg['action']['action1'] = dict() # msg['action']['action1'] = dict()
# msg['action']['action1']['title'] = 'Open Backup' # msg['action']['action1']['title'] = 'Open Backup'
# msg['action']['action1']['loc'] = 'file:~/backup' # msg['action']['action1']['loc'] = 'file:~/backup'
advnotify = Notification() advnotify = Notification()
advnotify.normal(msg) advnotify.normal(msg)
args.mdbd.critical(msg)
elif args.notification == None: elif args.notification == None:
logger.critical("No notification at all") logger.critical("No notification at all")
else: else:
logger.critical("No notification at all") logger.critical("No notification at all")
logger.critical("---== (%s) finnished %s %s at %s ==---" % (os.getpid(),args.func.__name__, args.tag, args.timestamp)) logger.critical("---== (%s) finnished %s %s at %s ==---" % (os.getpid(),args.func.__name__, args.tag, args.timestamp))
args.mdb.finished(args.tag) args.mdb.finished(args.tag)
#import ntfy #import ntfy
# import smtplib # import smtplib
# server = smtplib.SMTP('localhost', 587) # server = smtplib.SMTP('localhost', 587)
# #
@ -2154,4 +2168,4 @@ http://www.google.com
# msg = """ # msg = """
# Hello!""" # The /n separates the message from the headers # Hello!""" # The /n separates the message from the headers
# server.sendmail("first.recipient@provider1.example", "second.recipient@provider2.example", msg) # server.sendmail("first.recipient@provider1.example", "second.recipient@provider2.example", msg)
# #header