mirror of
				https://github.com/CumulusNetworks/ifupdown2.git
				synced 2024-05-06 15:54:50 +00:00 
			
		
		
		
	to make sure the state file in persistent storage is cleaned up correctly Ticket: CM-7774 Reviewed By: CCR-3623 Testing Done: Tested statefile accross reboots ifupdown2 state file was moved to /var/tmp because /var/tmp was tmpfs and was large enough (100MB) for the state file. But it appears it has changed (or is not consistent) across all platforms. We can move it under /run, but /run again size varies on various platforms and it is too small on some platforms. This patch: - continues to keep the ifupdown2 state file under /var/tmp (because it needs the space) - ntroduces a second level /run/network/ifstatelock file that stays on non-persistant storage and is used to delete the state file at /boot up
		
			
				
	
	
		
			188 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			188 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| #!/usr/bin/python
 | |
| #
 | |
| # Copyright 2014 Cumulus Networks, Inc. All rights reserved.
 | |
| # Author: Roopa Prabhu, roopa@cumulusnetworks.com
 | |
| #
 | |
| # stateManager --
 | |
| #    interface state manager
 | |
| #
 | |
| import cPickle
 | |
| from collections import OrderedDict
 | |
| import logging
 | |
| import os
 | |
| from iface import *
 | |
| 
 | |
| class pickling():
 | |
|     """ class with helper methods for pickling/unpickling iface objects """
 | |
| 
 | |
|     @classmethod
 | |
|     def save(cls, filename, list_of_objects):
 | |
|         """ pickle a list of iface objects """
 | |
|         try:
 | |
|             with open(filename, 'w') as f:
 | |
|                 for obj in list_of_objects:
 | |
|                     cPickle.dump(obj, f, cPickle.HIGHEST_PROTOCOL)
 | |
|         except:
 | |
|             raise
 | |
| 
 | |
|     @classmethod
 | |
|     def save_obj(cls, f, obj):
 | |
|         """ pickle iface object """
 | |
|         try:
 | |
|             cPickle.dump(obj, f, cPickle.HIGHEST_PROTOCOL)
 | |
|         except:
 | |
|             raise
 | |
| 
 | |
|     @classmethod
 | |
|     def load(cls, filename):
 | |
|         """ load picked iface object """
 | |
|         with open(filename, 'r') as f:
 | |
|             while True:
 | |
|                 try: yield cPickle.load(f)
 | |
|                 except EOFError: break
 | |
|                 except: raise
 | |
| 
 | |
| class stateManager():
 | |
|     """ state manager for managing ifupdown iface obj state
 | |
| 
 | |
|     ifupdown2 has to maitain old objects for down operation on
 | |
|     interfaces. ie to down or delete old configuration.
 | |
| 
 | |
|     This class uses pickle to store iface objects.
 | |
| 
 | |
|     """
 | |
| 
 | |
|     state_dir = '/var/tmp/network/'
 | |
|     """directory where the state file is stored """
 | |
| 
 | |
|     state_filename = 'ifstatenew'
 | |
|     """name of the satefile """
 | |
| 
 | |
|     state_rundir = '/run/network/'
 | |
|     """name of the state run dir """
 | |
| 
 | |
|     state_runlockfile = 'ifstatelock'
 | |
|     """name of the state run lock file """
 | |
| 
 | |
|     def __init__(self):
 | |
|         """ Initializes statemanager internal state
 | |
| 
 | |
|         which includes a dictionary of last pickled iface objects
 | |
|         """
 | |
|         self.ifaceobjdict = OrderedDict()
 | |
|         self.logger = logging.getLogger('ifupdown.' +
 | |
|                     self.__class__.__name__)
 | |
|         if not os.path.exists(self.state_dir):
 | |
|             os.mkdir(self.state_dir)
 | |
|         if not os.path.exists(self.state_rundir):
 | |
|             os.mkdir(self.state_rundir)
 | |
|         self.state_file = self.state_dir + self.state_filename
 | |
| 
 | |
|     def save_ifaceobj(self, ifaceobj):
 | |
|         self.ifaceobjdict.setdefault(ifaceobj.name,
 | |
|                             []).append(ifaceobj)
 | |
| 
 | |
|     def read_saved_state(self, filename=None):
 | |
|         """This member function reads saved iface objects
 | |
| 
 | |
|         Kwargs:
 | |
|             filename (str): name of the state file
 | |
|         """
 | |
| 
 | |
|         pickle_filename = filename
 | |
|         if not pickle_filename:
 | |
|             pickle_filename = self.state_file
 | |
|         if not os.path.exists(pickle_filename):
 | |
|             return
 | |
|         for ifaceobj in pickling.load(pickle_filename):
 | |
|             self.save_ifaceobj(ifaceobj)
 | |
| 
 | |
|     def get_ifaceobjs(self, ifacename):
 | |
|         return self.ifaceobjdict.get(ifacename)
 | |
| 
 | |
|     def ifaceobj_sync(self, ifaceobj, op):
 | |
|         """This member function sync's new obj state to old statemanager state
 | |
| 
 | |
|         Args:
 | |
|             ifaceobj (object): new iface object
 | |
|             op (str): ifupdown operation
 | |
|         """
 | |
| 
 | |
|         self.logger.debug('%s: statemanager sync state %s'
 | |
|                           %(ifaceobj.name, op))
 | |
|         old_ifaceobjs = self.ifaceobjdict.get(ifaceobj.name)
 | |
|         if 'up' in op:
 | |
|             if not old_ifaceobjs:
 | |
|                 self.ifaceobjdict[ifaceobj.name] = [ifaceobj]
 | |
|             else:
 | |
|                 # If it matches any of the object, return
 | |
|                 if any(o.compare(ifaceobj) for o in old_ifaceobjs):
 | |
|                     return
 | |
|                 # If it does not match any of the objects, and if
 | |
|                 # all objs in the list came from the pickled file,
 | |
|                 # then reset the list and add this object as a fresh one,
 | |
|                 # else append to the list
 | |
|                 if old_ifaceobjs[0].flags & iface._PICKLED:
 | |
|                     del self.ifaceobjdict[ifaceobj.name]
 | |
|                     self.ifaceobjdict[ifaceobj.name] = [ifaceobj]
 | |
|                 else:
 | |
|                     self.ifaceobjdict[ifaceobj.name].append(ifaceobj)
 | |
|         elif 'down' in op:
 | |
|             # If down of object successfull, delete object from state manager
 | |
|             if not old_ifaceobjs:
 | |
|                 return
 | |
|             if ifaceobj.status != ifaceStatus.SUCCESS:
 | |
|                 return
 | |
|             # If it matches any of the object, return
 | |
|             oidx = 0
 | |
|             for o in old_ifaceobjs:
 | |
|                 if o.compare(ifaceobj):
 | |
|                     old_ifaceobjs.pop(oidx)
 | |
|                     if not len(old_ifaceobjs):
 | |
|                         del self.ifaceobjdict[ifaceobj.name]
 | |
|                     return
 | |
|                 oidx += 1
 | |
| 
 | |
|     def save_state(self):
 | |
|         """ saves state (ifaceobjects) to persistent state file """
 | |
| 
 | |
|         try:
 | |
|             with open(self.state_file, 'w') as f:
 | |
|                 if not len(self.ifaceobjdict):
 | |
|                     f.truncate(0)
 | |
|                     return
 | |
|                 self.logger.debug('saving state ..')
 | |
|                 for ifaceobjs in self.ifaceobjdict.values():
 | |
|                     [pickling.save_obj(f, i) for i in ifaceobjs]
 | |
|             open('%s/%s' %(self.state_rundir, self.state_runlockfile), 'w').close()
 | |
|         except:
 | |
|             raise
 | |
| 
 | |
|     def dump_pretty(self, ifacenames, format='native'):
 | |
|         if not ifacenames:
 | |
|             ifacenames = self.ifaceobjdict.keys()
 | |
|         for i in ifacenames:
 | |
|             ifaceobjs = self.get_ifaceobjs(i)
 | |
|             if not ifaceobjs:
 | |
|                 continue
 | |
|             for ifaceobj in ifaceobjs:
 | |
|                 if format == 'json':
 | |
|                     ifaceobj.dump_json()
 | |
|                 else:
 | |
|                     ifaceobj.dump_pretty()
 | |
| 
 | |
|     def dump(self, ifacenames=None):
 | |
|         self.logger.debug('statemanager iface state:')
 | |
|         if ifacenames:
 | |
|             for i in ifacenames:
 | |
|                 ifaceobj = self.ifaces.get(i)
 | |
|                 if ifaceobj is None:
 | |
|                     raise ifaceNotFoundError('ifname %s'
 | |
|                         %i + ' not found')
 | |
|                 ifaceobj.dump(self.logger)
 | |
|         else:
 | |
|             for ifacename, ifaceobjs in self.ifaceobjdict.items():
 | |
|                 [i.dump(self.logger) for i in ifaceobjs]
 | |
| 
 | |
| statemanager_api = stateManager()
 |