update_backup_copy_stats.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. #!/usr/bin/python3
  2. # -*- coding: utf-8 -*-
  3. # $Id: btrfs-diskusage.py,v 1.1 2022/10/17 07:53:20 springm Exp springm $
  4. # $Revision: 1.1 $
  5. # $Date: 2022/10/17 07:53:20 $
  6. # $Log: btrfs-diskusage.py,v $
  7. # Revision 1.1 2022/10/17 07:53:20 springm
  8. # Initial revision
  9. '''
  10. * (shell) Lokaler Mount der Backup-Kopie
  11. * backup_the_backup.sh muss als root laufen.
  12. * rsync-kopiere repository von hermes (backup_the_backup.sh)
  13. /var/lib/restic und /var/lib/restic/backupcopies.json auf hermes
  14. müssen für springm beschreibbar sein
  15. * Hole json-file per scp von hermes
  16. * update json-file lokal
  17. * Eintrag mit aktuellem Datum
  18. * __summary updaten
  19. * kopiere json-file per scp auf hermes
  20. * umount der Backup-Kopie
  21. '''
  22. # ------------------------------------------- start script variables ---
  23. remotehost = 'r-hermes'
  24. remoterepo = '/backupdisk/backupdisk/restic-repo'
  25. json_remotefile = '/var/lib/restic/backupcopies.json'
  26. json_localfile = '/tmp/backupcopies.json'
  27. # UUID ermitteln mit blkid
  28. snapcolors = { 'a0942a33-911d-429f-9e7d-cf38f3730525' : 'blau',
  29. '1faf4622-fd5d-4cde-8d6a-8c9e9b0c7c5b' : 'violett' }
  30. # --------------------------------------------- end script variables ---
  31. import argparse
  32. import datetime
  33. from datetime import datetime, timedelta, timezone
  34. import json
  35. import re
  36. import socket
  37. import subprocess
  38. import sys
  39. from paramiko import SSHClient
  40. from scp import SCPClient
  41. jso = {}
  42. def load_jsonfile( ):
  43. try:
  44. with SCPClient(ssh.get_transport()) as scp:
  45. scp.get(json_remotefile, local_path=json_localfile)
  46. with open(json_localfile, 'r') as openfile:
  47. jso = json.load(openfile)
  48. except:
  49. print(f"Warning: could not get {json_remotefile} from {remotehost}")
  50. def disc_free ( mountpoint, host ):
  51. if host != False:
  52. # cmd = [ 'ssh', host, 'bash', '-c', f"df | grep {mountpoint} | cut -b 57-68,70-72" ]
  53. cmd = [ 'ssh', host, 'bash', '-c', f"df | grep {mountpoint} | cut -b 52-61,64-68" ]
  54. s = subprocess.check_output( cmd ).decode('utf-8').strip().split(' ')
  55. print("-".join(s))
  56. else:
  57. cmd = [ 'bash', '-c', f"df | grep {mountpoint} | cut -b 51-61,64-66" ]
  58. s = subprocess.check_output( cmd ).decode('utf-8').strip().split(' ')
  59. return( { 'fill_level' : s[1], 'bytes_free' : s[0] } )
  60. def disc_blkid ( mapperdev, host ):
  61. if host != False:
  62. cmd = [ 'ssh', host, f"""lsblk -n -o UUID {mapperdev}"""]
  63. s = subprocess.check_output( cmd ).decode('utf-8')
  64. else:
  65. cmd = [ 'bash', '-c', f"""lsblk -n -o UUID {mapperdev}"""]
  66. s = subprocess.check_output( cmd ).decode('utf-8')
  67. s = s.strip("\n")
  68. return(s)
  69. def nextcolor ( blkid ):
  70. for key in snapcolors:
  71. if key != blkid:
  72. return snapcolors[key]
  73. def update_json ():
  74. now = str(datetime.fromisoformat(args.repolastupdate))
  75. jso[now] = {}
  76. r_blkid = disc_blkid('/dev/mapper/backupdisk', remotehost)
  77. jso[now][r_blkid] = {}
  78. jso[now][r_blkid]['backup_server'] = remotehost
  79. jso[now][r_blkid]['bytes_free'] = disc_free('/backupdisk', remotehost)['bytes_free']
  80. jso[now][r_blkid]['fill_level'] = disc_free('/backupdisk', remotehost)['fill_level']
  81. print(jso[now][r_blkid]['fill_level'])
  82. localdevice = subprocess.check_output(['/usr/bin/grep', args.localrepobasedir, '/proc/mounts']).decode('utf-8').split()[0]
  83. blkid = disc_blkid(localdevice, False) # localhost
  84. jso[now][blkid] = {}
  85. jso[now][blkid]['bytes_free'] = disc_free(args.localrepobasedir, False)['bytes_free']
  86. jso[now][blkid]['fill_level'] = disc_free(args.localrepobasedir, False)['fill_level']
  87. jso[now][blkid]['color'] = snapcolors[blkid]
  88. jso['__summary'] = { 'last_backup_copy' : now,
  89. 'last_backup_blkid' : blkid,
  90. 'last_backup_color' : snapcolors[blkid],
  91. 'last_remotefreebytes' : jso[now][r_blkid]['bytes_free'],
  92. 'last_localfreebytes' : jso[now][blkid]['bytes_free'],
  93. 'last_remotefilllevel' : jso[now][r_blkid]['fill_level'],
  94. 'last_localfilllevel' : jso[now][blkid]['fill_level'],
  95. 'next_backup_color' : nextcolor(blkid) }
  96. def write_json():
  97. with open(json_localfile, 'w', encoding='utf-8') as f:
  98. json.dump(jso, f, ensure_ascii=False, indent=4)
  99. try:
  100. with SCPClient(ssh.get_transport()) as scp:
  101. scp.put(json_localfile, json_remotefile)
  102. except:
  103. print(f"Error: could not copy {json_localfile} to {remotehost}:{json_remotefile}")
  104. def rewrite_snapshots_json(host):
  105. cmd = [ 'ssh', host, 'bash', '-c', "/usr/local/sbin/restic_json.sh" ]
  106. s = subprocess.check_output( cmd ).decode('utf-8').strip().split(' ')
  107. print(" ".join(s))
  108. # ------------------------------------------------------------- main ---
  109. parser = argparse.ArgumentParser(
  110. prog = sys.argv[0],
  111. description = 'Update json file of backup-of-backup stats',
  112. epilog = 'Markus ist ein cooler Hund')
  113. parser.add_argument('--localrepobasedir', help='local basedir of restic repo', required=True)
  114. parser.add_argument('--repolastupdate', help='last update timestamp of repo in full iso format', required=True)
  115. args = parser.parse_args()
  116. ssh = SSHClient()
  117. ssh.load_system_host_keys()
  118. ssh.connect(remotehost)
  119. load_jsonfile()
  120. update_json()
  121. #print(json.dumps(jso, sort_keys=True, indent=4))
  122. write_json()
  123. rewrite_snapshots_json(remotehost)