#!/usr/bin/env python3

# Copyright (c) 2019 Arista Networks, Inc.  All rights reserved.
# Arista Networks, Inc. Confidential and Proprietary.

import os
import shutil
import Tac

FLASH_PERSIST_DIR = '/mnt/flash/persist'

def needDir( d ):
   if not os.path.exists( d ):
      os.makedirs( d )

def SetupPersist( flashPersistDir=FLASH_PERSIST_DIR ):
   statRoot = Tac.run( [ 'stat', '-f', '-c', '%T', '/' ], stdout=Tac.CAPTURE )
   fsType = statRoot.strip()
   if fsType == 'nfs':
      return

   assert os.path.exists( '/mnt/flash' )

   # Create /persist/{local,sys,secure}, unpack persistent data archives, and
   # start inotifyrun daemons to automatically update the archives
   # /persist/secure has an extra scrub command to securely delete previous
   # data before it is backed up
   needDir( flashPersistDir )

   for subdir in [ 'local', 'sys', 'secure' ]:
      d = os.path.join( '/persist', subdir )
      needDir( d )
      os.chmod( d, 0o0777 )

      targetPath = os.path.join( flashPersistDir, subdir )
      newPath = '%s.new' % targetPath # pylint: disable=consider-using-f-string
      oldPath = '%s.old' % targetPath # pylint: disable=consider-using-f-string

      print( f'Restoring from {targetPath} to {d}' )
      if not os.path.exists( targetPath ) and os.path.exists( newPath ):
         try:
            shutil.move( newPath, targetPath )
         except shutil.Error as e:
            print( f'new {subdir} archive exists: {e}' )

      if os.path.exists( oldPath ):
         if os.path.exists( targetPath ):
            try:
               Tac.run( [ 'scrub', '--no-signature', '--remove', oldPath ] )
            except Tac.SystemCommandError as e:
               print( f'old {subdir} archive exists: {e}' )
         else:
            try:
               shutil.move( oldPath, targetPath )
            except OSError as e:
               print( f'{subdir} archive missing, old archive exists: {e}' )

      if os.path.exists( targetPath ):
         oldWd = os.getcwd()
         try:
            os.chdir( d )
            Tac.run( [ 'pax', '-r', '-p', 'e', '-f', targetPath ] )
         except Tac.SystemCommandError:
            # pylint: disable-next=consider-using-f-string
            print( '%s archive seems to be corrupted. Skipping.' % subdir )
         finally:
            os.chdir( oldWd )

      paxBackupCommand = (
         'date; pax -x sv4cpio -O -w -f {0}.new . '
         '&& mv {0}.new {0}'
         ' || logger -t SetupPersist Failed to update {0}'
      )

      if subdir == 'secure':
         # Make a file for scrub to work with initially
         open( targetPath, 'w' ).close() # pylint: disable=consider-using-with

         paxBackupCommand = (
            'date; pax -x sv4cpio -O -w -f {0}.new . && sync'
            ' && ( mv {0} {0}.old; mv {0}.new {0}; sync )'
            ' && ( scrub --no-signature {0}.old; rm {0}.old )'
            ' || logger -t SetupPersist Failed to update {0}'
         )

      Tac.run( [ 'inotifyrun',
                 '-c', paxBackupCommand.format( targetPath ),
                 '--daemon',
                 '--ratelimit', '0.5',
                 # pylint: disable-next=consider-using-f-string
                 '--logfile=/var/log/inotifyrun-%s.log' % subdir,
                 # pylint: disable-next=consider-using-f-string
                 '--pidfile=/var/run/inotifyrun-%s.pid' % subdir,
                 d ] )

if __name__ == "__main__":
   SetupPersist()
