]> git.proxmox.com Git - mirror_ifupdown2.git/blob - ifupdown2/ifupdown/statemanager.py
addons: addressvirtual: keep macvlan down if link-down specified on lower device
[mirror_ifupdown2.git] / ifupdown2 / ifupdown / statemanager.py
1 #!/usr/bin/python
2 #
3 # Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
5 #
6 # stateManager --
7 # interface state manager
8 #
9
10 import os
11 import cPickle
12 import logging
13
14 try:
15 from ifupdown2.ifupdown.iface import *
16
17 import ifupdown2.ifupdown.exceptions as exceptions
18 import ifupdown2.ifupdown.ifupdownconfig as ifupdownConfig
19 except ImportError:
20 from ifupdown.iface import *
21
22 import ifupdown.exceptions as exceptions
23 import ifupdown.ifupdownconfig as ifupdownConfig
24
25
26 class pickling():
27 """ class with helper methods for pickling/unpickling iface objects """
28
29 @classmethod
30 def save(cls, filename, list_of_objects):
31 """ pickle a list of iface objects """
32 try:
33 with open(filename, 'w') as f:
34 for obj in list_of_objects:
35 cPickle.dump(obj, f, cPickle.HIGHEST_PROTOCOL)
36 except:
37 raise
38
39 @classmethod
40 def save_obj(cls, f, obj):
41 """ pickle iface object """
42 try:
43 cPickle.dump(obj, f, cPickle.HIGHEST_PROTOCOL)
44 except:
45 raise
46
47 @classmethod
48 def load(cls, filename):
49 """ load picked iface object """
50 with open(filename, 'r') as f:
51 while True:
52 try: yield cPickle.load(f)
53 except EOFError: break
54 except: raise
55
56 class stateManager():
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 """
65
66 __DEFAULT_STATE_DIR = "/run/network/"
67
68 state_filename = 'ifstatenew'
69 """name of the satefile """
70
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
77 def __init__(self):
78 """ Initializes statemanager internal state
79
80 which includes a dictionary of last pickled iface objects
81 """
82 self.state_dir = None
83 self.state_file = None
84 self.ifaceobjdict = OrderedDict()
85 self.logger = logging.getLogger('ifupdown.' +
86 self.__class__.__name__)
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
110 if not os.path.exists(self.state_rundir):
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
119
120 def save_ifaceobj(self, ifaceobj):
121 self.ifaceobjdict.setdefault(ifaceobj.name,
122 []).append(ifaceobj)
123
124 def read_saved_state(self, filename=None):
125 """This member function reads saved iface objects
126
127 Kwargs:
128 filename (str): name of the state file
129 """
130
131 pickle_filename = filename
132 if not pickle_filename:
133 pickle_filename = self.state_file
134 if not os.path.exists(pickle_filename):
135 return
136 for ifaceobj in pickling.load(pickle_filename):
137 self.save_ifaceobj(ifaceobj)
138
139 def get_ifaceobjs(self, ifacename):
140 return self.ifaceobjdict.get(ifacename)
141
142 def ifaceobj_sync(self, ifaceobj, op):
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
150 self.logger.debug('%s: statemanager sync state %s'
151 %(ifaceobj.name, op))
152 old_ifaceobjs = self.ifaceobjdict.get(ifaceobj.name)
153 if 'up' in op:
154 if not old_ifaceobjs:
155 self.ifaceobjdict[ifaceobj.name] = [ifaceobj]
156 else:
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
184
185 def save_state(self):
186 """ saves state (ifaceobjects) to persistent state file """
187
188 try:
189 with open(self.state_file, 'w') as f:
190 if not len(self.ifaceobjdict):
191 f.truncate(0)
192 return
193 self.logger.debug('saving state ..')
194 for ifaceobjs in self.ifaceobjdict.values():
195 [pickling.save_obj(f, i) for i in ifaceobjs]
196 open('%s/%s' %(self.state_rundir, self.state_runlockfile), 'w').close()
197 except:
198 raise
199
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()
212
213 def dump(self, ifacenames=None):
214 self.logger.debug('statemanager iface state:')
215 if ifacenames:
216 for i in ifacenames:
217 ifaceobj = self.ifaces.get(i)
218 if ifaceobj is None:
219 raise exceptions.ifaceNotFoundError('ifname %s'
220 % i + ' not found')
221 ifaceobj.dump(self.logger)
222 else:
223 for ifacename, ifaceobjs in self.ifaceobjdict.items():
224 [i.dump(self.logger) for i in ifaceobjs]
225
226 statemanager_api = stateManager()
227
228 def reset():
229 global statemanager_api
230 statemanager_api = stateManager()