1
2
3
4
5
6
7
8
9
10
11 from Products.ZenMessaging.audit import audit
12 from Products.ZenUtils.deprecated import deprecated
13
14 __doc__="""Commandable
15
16 Mixin class for classes that need a relationship back from UserCommand.
17
18 """
19
20 from Globals import InitializeClass
21 from AccessControl import ClassSecurityInfo
22 from ZenossSecurity import *
23 from UserCommand import UserCommand
24 from Acquisition import aq_base, aq_chain
25 from Products.PageTemplates.Expressions import getEngine
26 from Products.ZenUtils.ZenTales import talesCompile
27 from Products.ZenUtils.Utils import unused
28 from Products.ZenWidgets import messaging
29 from DateTime import DateTime
30 import os
31 import popen2
32 import fcntl
33 import select
34 import signal
35 import time
36 import cgi
37 import sys
38
39 import logging
40 log = logging.getLogger("zen.Device")
43
44 defaultTimeout = 60
45
46 security = ClassSecurityInfo()
47
48 security.declareProtected(ZEN_DEFINE_COMMANDS_EDIT, 'manage_addUserCommand')
73
74
75 security.declareProtected(ZEN_DEFINE_COMMANDS_EDIT,
76 'manage_deleteUserCommand')
93
94 security.declareProtected(ZEN_DEFINE_COMMANDS_EDIT,
95 'manage_editUserCommand')
114
115
116 security.declareProtected(ZEN_RUN_COMMANDS, 'manage_doUserCommand')
117 @deprecated
119 ''' Execute a UserCommand. If REQUEST then
120 wrap output in proper zenoss html page.
121 '''
122
123
124
125
126 command = self.getUserCommands(asDict=True).get(commandId,None)
127 if not command:
128 if REQUEST:
129 return self.redirectToUserCommands(REQUEST)
130 if REQUEST:
131 REQUEST['cmd'] = command
132 header, footer = self.commandOutputTemplate().split('OUTPUT_TOKEN')
133 REQUEST.RESPONSE.write(str(header))
134 out = REQUEST.RESPONSE
135 else:
136 out = None
137
138 startTime = time.time()
139 numTargets = 0
140 for target in self.getUserCommandTargets():
141 numTargets += 1
142 try:
143 self.write(out, '')
144 self.write(out, '==== %s ====' % target.id)
145 self.doCommandForTarget(command, target, out)
146
147 audit('UI.Command.Invoke', commandId, target=target)
148 except:
149 self.write(out,
150 'exception while performing command for %s' % target.id)
151 self.write(
152 out, 'type: %s value: %s' % tuple(sys.exc_info()[:2]))
153 self.write(out, '')
154 self.write(out, '')
155 self.write(out, 'DONE in %s seconds on %s targets' %
156 (long(time.time() - startTime), numTargets))
157 REQUEST.RESPONSE.write(str(footer))
158
159
161 ''' Execute the given UserCommand on the given target
162 '''
163 compiled = self.compile(cmd, target)
164 child = popen2.Popen4(compiled)
165 flags = fcntl.fcntl(child.fromchild, fcntl.F_GETFL)
166 fcntl.fcntl(child.fromchild, fcntl.F_SETFL, flags | os.O_NDELAY)
167 timeout = getattr(target, 'zCommandCommandTimeout', self.defaultTimeout)
168 timeout = max(timeout, 1)
169 endtime = time.time() + timeout
170 self.write(out, '%s' % compiled)
171 self.write(out, '')
172 pollPeriod = 1
173 firstPass = True
174 while time.time() < endtime and (firstPass or child.poll() == -1):
175 firstPass = False
176 r, w, e = select.select([child.fromchild], [], [], pollPeriod)
177 if r:
178 t = child.fromchild.read()
179
180
181
182 if t:
183 self.write(out, t)
184
185 if child.poll() == -1:
186 self.write(out, 'Command timed out for %s' % target.id +
187 ' (timeout is %s seconds)' % timeout)
188 os.kill(child.pid, signal.SIGKILL)
189
190
208
209
210 security.declareProtected(ZEN_VIEW, 'getUserCommandIds')
212 ''' Get the user command ids available in this context
213 '''
214 commandIds = []
215 mychain = self.getAqChainForUserCommands()
216 mychain.reverse()
217 for obj in mychain:
218 if getattr(aq_base(obj), 'userCommands', None):
219 for c in obj.userCommands():
220 commandIds.append(c.id)
221 return commandIds
222
223 security.declareProtected(ZEN_DEFINE_COMMANDS_VIEW, 'getUserCommands')
225 ''' Get the user commands available in this context
226 '''
227 commands = {}
228 mychain = self.getAqChainForUserCommands()
229 mychain.reverse()
230 for obj in mychain:
231 if getattr(aq_base(obj), 'userCommands', None):
232 for c in obj.userCommands():
233 commands[c.id] = c
234 if not asDict:
235 commands = sorted(commands.itervalues(), key=lambda cmd: cmd.getId())
236 return commands
237
238
241
242
252
253
255 ''' Return url for page which manages user commands
256 '''
257
258 return self.getPrimaryUrlPath()
259
260 security.declareProtected(ZEN_DEFINE_COMMANDS_VIEW, 'getUserCommand')
262 ''' Returns the command from the current context if it exists
263 '''
264 return self.getUserCommands(asDict=True).get(commandId, None)
265
266
268 ''' Get the environment that provides context for the tales
269 evaluation of a UserCommand.
270 '''
271
272 return {
273 'target': self,
274 'here': self,
275 'nothing': None,
276 'now': DateTime()
277 }
278
279
281 ''' Called by Commandable.doCommand() to ascertain objects on which
282 a UserCommand should be executed.
283 '''
284 raise NotImplemented
285
286
287 - def write(self, out, lines):
288 ''' Output (maybe partial) result text from a UserCommand.
289 '''
290
291
292
293
294
295
296
297
298 startLine = '<tr><td class="commandoutput">'
299 endLine = '\n</td></tr>\n'
300 if out:
301 if not isinstance(lines, list):
302 lines = [lines]
303 for l in lines:
304 if not isinstance(l, str):
305 l = str(l)
306 l = l.strip()
307 l = cgi.escape(l)
308 l = l.replace('\n', endLine + startLine)
309 out.write(startLine + l + endLine)
310
311
312
313 InitializeClass(Commandable)
314