1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 __doc__='''Schedule
16
17 Walk through the maintenance schedule.
18
19 $Id$
20 '''
21
22 import time
23 import logging
24 from twisted.internet import reactor
25
26 from ZODB.transact import transact
27 from Products.ZenEvents.ZenEventClasses import Status_Update
28 from Products.ZenEvents import Event
31
33 "start executing the schedule"
34 self.dmd = dmd
35 self.maintenance = []
36 self.options = options
37 self.log = logging.getLogger("zen.Schedule")
38 self.workList = []
39 self.timer = None
40
41
43 "Set options in a borrowed parser"
44
45
49
50
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
133
134 now = self.now()
135 work = self.makeWorkList(now, self.workList)
136 self.workList = [mw for t, mw in work]
137
138 for next, mw in work:
139 if next <= now:
140 how = {True:'stopping', False:'starting'}[bool(mw.started)]
141 severity = {True:Event.Clear, False:Event.Info}[bool(mw.started)]
142
143
144
145 prodState = {True:-99, False:mw.startProductionState}[bool(mw.started)]
146 mwId = mw.getId()
147 devices = mw.target().getId()
148 msg = "Maintenance window %s %s for %s" % (how, mwId, devices)
149 self.log.debug(msg)
150 dedupid = '|'.join(["zenjobs",self.monitor,mwId,devices])
151 self.sendEvent(Event.Event(
152 component="zenjobs",
153 severity=severity,
154 dedupid=dedupid,
155 eventClass=Status_Update,
156 eventClassKey="mw_change",
157 summary=msg,
158 eventKey='|'.join([mwId,devices]),
159 maintenance_window=mwId,
160 maintenance_devices=devices,
161 device=self.monitor,
162 prodState=prodState,
163 ))
164 self.executeMaintenanceWindow(mw, next)
165 else:
166 break
167
168 work = self.makeWorkList(now, self.workList)
169 if work:
170 wait = max(0, work[0][0] - now)
171 self.log.debug("Waiting %f seconds", wait)
172 self.timer = self.callLater(wait)
173
176
177 @transact
178 - def executeMaintenanceWindow(self, mw, timestamp):
180
181 if __name__ == "__main__":
199
200 import Globals
201 from Products.ZenUtils.ZCmdBase import ZCmdBase
202
203 cmd = ZCmdBase()
205 s = MySchedule(Options(), cmd.dmd)
206
207 end = s.currentTime + 60*60*24*30
208 while s.currentTime < end:
209 s.run()
210