1
2
3
4
5
6
7
8
9
10
11
12 __doc__='''Schedule
13
14 Walk through the maintenance schedule.
15
16 $Id$
17 '''
18
19 import time
20 import logging
21 from twisted.internet import reactor
22
23 from ZODB.transact import transact
24 from Products.ZenEvents.ZenEventClasses import Status_Update
25 from Products.ZenEvents import Event
28
30 "start executing the schedule"
31 self.dmd = dmd
32 self.maintenance = []
33 self.options = options
34 self.log = logging.getLogger("zen.Schedule")
35 self.workList = []
36 self.timer = None
37
38
40 "Set options in a borrowed parser"
41
42
46
47
49 "Basic event-driven config loop"
50 try:
51 self.run()
52 except Exception:
53 self.log.exception("Error processing maintenance windows - will try again in % seconds", self.options.maintenceWindowCycletime)
54 reactor.callLater(self.options.maintenceWindowCycletime, self.configCycle)
55
56
58 "Synch with the database"
59 self.dmd._p_jar.sync()
60
62 result = []
63 catalog = getattr(self.dmd, 'maintenanceWindowSearch', None)
64 if catalog is not None:
65 for brain in catalog():
66 try:
67 ob = brain.getObject()
68 except KeyError:
69
70
71
72 pass
73 else:
74 result.append(ob)
75 else:
76 self.log.warn('Run zenmigrate to index your maintenance windows.')
77 for dev in self.dmd.Devices.getSubDevices():
78 result.extend(dev.maintenanceWindows())
79 for name in 'Systems', 'Locations', 'Groups', 'Devices':
80 organizer = getattr(self.dmd, name)
81 for c in organizer.getSubOrganizers():
82 result.extend(c.maintenanceWindows())
83 result.extend(organizer.maintenanceWindows())
84 for lst in [self.dmd.ZenUsers.getAllUserSettings(),
85 self.dmd.ZenUsers.getAllGroupSettings()]:
86 for us in lst:
87 for ar in us.objectValues(spec="ActionRule"):
88 result.extend(w for w in ar.windows() if w.enabled)
89 return result
90
96
97
98 @transact
100 """
101 Returns the list of tuples where 0 is the next time the
102 window should run and the 1 index is the window itself.
103 If there is no next run and the window has started this
104 method ends the windows.
105
106 This method is wrapped in a transact block because there
107 is the chance that we could set the production state on
108 devices if the "end" method is called.
109 """
110 work = [(mw.nextEvent(now), mw) for mw in workList]
111 work.sort()
112
113 while len(work):
114 t, mw = work[0]
115 if t: break
116 if mw.enabled:
117 self.log.debug("Never going to run Maintenance "
118 "Window %s for %s again",
119 mw.getId(), mw.target().getId())
120 if mw.started:
121 mw.end()
122 work.pop(0)
123 return work
124
127
129 "Execute all the maintanance windows at the proper time"
130 if self.timer and not self.timer.called:
131 self.timer.cancel()
132 self.timer = None
133
134
135 now = self.now()
136 work = self.makeWorkList(now, self.workList)
137 self.workList = [mw for t, mw in work]
138
139 for next, mw in work:
140 if next <= now:
141 how = {True:'stopping', False:'starting'}[bool(mw.started)]
142 severity = {True:Event.Clear, False:Event.Info}[bool(mw.started)]
143
144
145
146 prodState = {True:-99, False:mw.startProductionState}[bool(mw.started)]
147 mwId = mw.getId()
148 devices = mw.target().getId()
149 msg = "Maintenance window %s %s for %s" % (how, mwId, devices)
150 self.log.debug(msg)
151 dedupid = '|'.join(["zenjobs",self.monitor,mwId,devices])
152 self.sendEvent(Event.Event(
153 component="zenjobs",
154 severity=severity,
155 dedupid=dedupid,
156 eventClass=Status_Update,
157 eventClassKey="mw_change",
158 summary=msg,
159 eventKey='|'.join([mwId,devices]),
160 maintenance_window=mwId,
161 maintenance_devices=devices,
162 device=self.monitor,
163 prodState=prodState,
164 ))
165 self.executeMaintenanceWindow(mw, next)
166 else:
167 break
168
169 work = self.makeWorkList(now, self.workList)
170 if work:
171 wait = max(0, work[0][0] - now)
172 self.log.debug("Waiting %f seconds", wait)
173 self.timer = self.callLater(wait)
174
177
178 @transact
179 - def executeMaintenanceWindow(self, mw, timestamp):
181
182 if __name__ == "__main__":
200
201 import Globals
202 from Products.ZenUtils.ZCmdBase import ZCmdBase
203
204 cmd = ZCmdBase()
206 s = MySchedule(Options(), cmd.dmd)
207
208 end = s.currentTime + 60*60*24*30
209 while s.currentTime < end:
210 s.run()
211