]>
Commit | Line | Data |
---|---|---|
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 | |
10 | import os | |
a6f80f0e | 11 | import cPickle |
a6f80f0e | 12 | import logging |
d486dd0d JF |
13 | |
14 | try: | |
15 | from ifupdown2.ifupdown.iface import * | |
16 | ||
17 | import ifupdown2.ifupdown.exceptions as exceptions | |
9f98f360 | 18 | import ifupdown2.ifupdown.ifupdownconfig as ifupdownConfig |
d486dd0d JF |
19 | except ImportError: |
20 | from ifupdown.iface import * | |
21 | ||
22 | import ifupdown.exceptions as exceptions | |
9f98f360 | 23 | import ifupdown.ifupdownconfig as ifupdownConfig |
d486dd0d | 24 | |
a6f80f0e | 25 | |
26 | class 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 | 56 | class 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 | |
226 | statemanager_api = stateManager() | |
d486dd0d JF |
227 | |
228 | def reset(): | |
229 | global statemanager_api | |
230 | statemanager_api = stateManager() |