]> git.proxmox.com Git - mirror_ifupdown2.git/blame - ifupdown2/ifupdown/statemanager.py
statemanager: configure state_dir via ifupdown2.conf
[mirror_ifupdown2.git] / ifupdown2 / ifupdown / statemanager.py
CommitLineData
a6f80f0e 1#!/usr/bin/python
3e8ee54f 2#
d486dd0d 3# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
3e8ee54f 4# Author: Roopa Prabhu, roopa@cumulusnetworks.com
5#
6# stateManager --
7# interface state manager
8#
d486dd0d
JF
9
10import os
a6f80f0e 11import cPickle
a6f80f0e 12import logging
d486dd0d
JF
13
14try:
15 from ifupdown2.ifupdown.iface import *
16
17 import ifupdown2.ifupdown.exceptions as exceptions
9f98f360 18 import ifupdown2.ifupdown.ifupdownconfig as ifupdownConfig
d486dd0d
JF
19except ImportError:
20 from ifupdown.iface import *
21
22 import ifupdown.exceptions as exceptions
9f98f360 23 import ifupdown.ifupdownconfig as ifupdownConfig
d486dd0d 24
a6f80f0e 25
26class pickling():
53b00224 27 """ class with helper methods for pickling/unpickling iface objects """
a6f80f0e 28
29 @classmethod
30 def save(cls, filename, list_of_objects):
2c0ad8b3 31 """ pickle a list of iface objects """
a6f80f0e 32 try:
33 with open(filename, 'w') as f:
34 for obj in list_of_objects:
5c721925 35 cPickle.dump(obj, f, cPickle.HIGHEST_PROTOCOL)
a6f80f0e 36 except:
37 raise
38
39 @classmethod
40 def save_obj(cls, f, obj):
2c0ad8b3 41 """ pickle iface object """
a6f80f0e 42 try:
5c721925 43 cPickle.dump(obj, f, cPickle.HIGHEST_PROTOCOL)
a6f80f0e 44 except:
45 raise
46
a6f80f0e 47 @classmethod
48 def load(cls, filename):
2c0ad8b3 49 """ load picked iface object """
a6f80f0e 50 with open(filename, 'r') as f:
51 while True:
52 try: yield cPickle.load(f)
53 except EOFError: break
54 except: raise
55
a6f80f0e 56class stateManager():
2c0ad8b3
RP
57 """ state manager for managing ifupdown iface obj state
58
59 ifupdown2 has to maitain old objects for down operation on
60 interfaces. ie to down or delete old configuration.
61
62 This class uses pickle to store iface objects.
63
64 """
a6f80f0e 65
9f98f360 66 __DEFAULT_STATE_DIR = "/run/network/"
2c0ad8b3 67
a690dfae 68 state_filename = 'ifstatenew'
2c0ad8b3 69 """name of the satefile """
a6f80f0e 70
a33e94f7
RP
71 state_rundir = '/run/network/'
72 """name of the state run dir """
73
74 state_runlockfile = 'ifstatelock'
75 """name of the state run lock file """
76
a6f80f0e 77 def __init__(self):
2c0ad8b3
RP
78 """ Initializes statemanager internal state
79
80 which includes a dictionary of last pickled iface objects
81 """
9f98f360
JF
82 self.state_dir = None
83 self.state_file = None
a6f80f0e 84 self.ifaceobjdict = OrderedDict()
85 self.logger = logging.getLogger('ifupdown.' +
86 self.__class__.__name__)
9f98f360
JF
87
88 def init(self):
89 self.state_dir = ifupdownConfig.config.get("state_dir")
90 used_default = False
91
92 if not self.state_dir:
93 self.logger.debug("statemanager: state_dir not defined in config file, using default: %s" % self.__DEFAULT_STATE_DIR)
94 self.state_dir = self.__DEFAULT_STATE_DIR
95 used_default = True
96
97 try:
98 self._init_makedirs_state_dir()
99 except Exception as e:
100 if used_default:
101 # if the default path was used but still throws an exception...
102 raise
103 self.logger.info("statemanager: %s: using default directory: %s" % (e, self.__DEFAULT_STATE_DIR))
104 self.state_dir = self.__DEFAULT_STATE_DIR
105 try:
106 self._init_makedirs_state_dir()
107 except Exception as e:
108 raise Exception("statemanager: unable to create required directory: %s" % str(e))
109
a33e94f7 110 if not os.path.exists(self.state_rundir):
9f98f360
JF
111 os.makedirs(self.state_rundir)
112
113 self.state_file = "%s/%s" % (self.state_dir, self.state_filename)
114
115 def _init_makedirs_state_dir(self):
116 if not os.path.exists(self.state_dir):
117 os.makedirs(self.state_dir)
118
a6f80f0e 119
120 def save_ifaceobj(self, ifaceobj):
62ddec8b 121 self.ifaceobjdict.setdefault(ifaceobj.name,
5c721925 122 []).append(ifaceobj)
a6f80f0e 123
124 def read_saved_state(self, filename=None):
2c0ad8b3
RP
125 """This member function reads saved iface objects
126
127 Kwargs:
128 filename (str): name of the state file
129 """
130
a6f80f0e 131 pickle_filename = filename
fe0a57d3 132 if not pickle_filename:
a6f80f0e 133 pickle_filename = self.state_file
a6f80f0e 134 if not os.path.exists(pickle_filename):
135 return
a6f80f0e 136 for ifaceobj in pickling.load(pickle_filename):
137 self.save_ifaceobj(ifaceobj)
a6f80f0e 138
5c721925 139 def get_ifaceobjs(self, ifacename):
140 return self.ifaceobjdict.get(ifacename)
141
cb7cc592 142 def ifaceobj_sync(self, ifaceobj, op):
2c0ad8b3
RP
143 """This member function sync's new obj state to old statemanager state
144
145 Args:
146 ifaceobj (object): new iface object
147 op (str): ifupdown operation
148 """
149
ee3fcf44
RP
150 self.logger.debug('%s: statemanager sync state %s'
151 %(ifaceobj.name, op))
53b00224 152 old_ifaceobjs = self.ifaceobjdict.get(ifaceobj.name)
cb7cc592 153 if 'up' in op:
154 if not old_ifaceobjs:
53b00224 155 self.ifaceobjdict[ifaceobj.name] = [ifaceobj]
31a5f4c3 156 else:
cb7cc592 157 # If it matches any of the object, return
158 if any(o.compare(ifaceobj) for o in old_ifaceobjs):
159 return
160 # If it does not match any of the objects, and if
161 # all objs in the list came from the pickled file,
162 # then reset the list and add this object as a fresh one,
163 # else append to the list
164 if old_ifaceobjs[0].flags & iface._PICKLED:
165 del self.ifaceobjdict[ifaceobj.name]
166 self.ifaceobjdict[ifaceobj.name] = [ifaceobj]
167 else:
168 self.ifaceobjdict[ifaceobj.name].append(ifaceobj)
169 elif 'down' in op:
170 # If down of object successfull, delete object from state manager
171 if not old_ifaceobjs:
172 return
173 if ifaceobj.status != ifaceStatus.SUCCESS:
174 return
175 # If it matches any of the object, return
176 oidx = 0
177 for o in old_ifaceobjs:
178 if o.compare(ifaceobj):
179 old_ifaceobjs.pop(oidx)
180 if not len(old_ifaceobjs):
181 del self.ifaceobjdict[ifaceobj.name]
182 return
183 oidx += 1
a6f80f0e 184
31a5f4c3 185 def save_state(self):
2c0ad8b3
RP
186 """ saves state (ifaceobjects) to persistent state file """
187
a6f80f0e 188 try:
189 with open(self.state_file, 'w') as f:
cb7cc592 190 if not len(self.ifaceobjdict):
525f0a30 191 f.truncate(0)
cb7cc592 192 return
525f0a30 193 self.logger.debug('saving state ..')
31a5f4c3 194 for ifaceobjs in self.ifaceobjdict.values():
53b00224 195 [pickling.save_obj(f, i) for i in ifaceobjs]
a33e94f7 196 open('%s/%s' %(self.state_rundir, self.state_runlockfile), 'w').close()
a6f80f0e 197 except:
198 raise
199
5c721925 200 def dump_pretty(self, ifacenames, format='native'):
201 if not ifacenames:
202 ifacenames = self.ifaceobjdict.keys()
203 for i in ifacenames:
204 ifaceobjs = self.get_ifaceobjs(i)
205 if not ifaceobjs:
206 continue
207 for ifaceobj in ifaceobjs:
208 if format == 'json':
209 ifaceobj.dump_json()
210 else:
211 ifaceobj.dump_pretty()
a6f80f0e 212
213 def dump(self, ifacenames=None):
31a5f4c3 214 self.logger.debug('statemanager iface state:')
fe0a57d3 215 if ifacenames:
a6f80f0e 216 for i in ifacenames:
217 ifaceobj = self.ifaces.get(i)
218 if ifaceobj is None:
afe51251 219 raise exceptions.ifaceNotFoundError('ifname %s'
d486dd0d 220 % i + ' not found')
a6f80f0e 221 ifaceobj.dump(self.logger)
222 else:
31a5f4c3 223 for ifacename, ifaceobjs in self.ifaceobjdict.items():
224 [i.dump(self.logger) for i in ifaceobjs]
55072bd1
ST
225
226statemanager_api = stateManager()
d486dd0d
JF
227
228def reset():
229 global statemanager_api
230 statemanager_api = stateManager()