1
2
3
4
5
6
7
8
9
10
11
12
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_parent, aq_chain
25 from Products.PageTemplates.Expressions import getEngine
26 from Products.ZenUtils.ZenTales import talesCompile
27 from DateTime import DateTime
28 import os
29 import popen2
30 import fcntl
31 import select
32 import signal
33 import time
34 import cgi
35 import sys
36 import traceback
37
38 import logging
39 log = logging.getLogger("zen.Device")
40
42
43 defaultTimeout = 60
44
45 security = ClassSecurityInfo()
46
47 security.declareProtected(ZEN_DEFINE_COMMANDS_EDIT, 'manage_addUserCommand')
66
67
68 security.declareProtected(ZEN_DEFINE_COMMANDS_EDIT,
69 'manage_deleteUserCommand')
82
83 security.declareProtected(ZEN_DEFINE_COMMANDS_EDIT,
84 'manage_editUserCommand')
92
93
94 security.declareProtected(ZEN_CHANGE_DEVICE, 'manage_doUserCommand')
96 ''' Execute a UserCommand. If REQUEST then
97 wrap output in proper zenoss html page.
98 '''
99
100
101
102 command = self.getUserCommands(asDict=True).get(commandId,None)
103 if not command:
104 if REQUEST:
105 return self.redirectToUserCommands(REQUEST)
106 if REQUEST:
107 REQUEST['cmd'] = command
108 header, footer = self.commandOutputTemplate().split('OUTPUT_TOKEN')
109 REQUEST.RESPONSE.write(str(header))
110 out = REQUEST.RESPONSE
111 else:
112 out = None
113
114 startTime = time.time()
115 numTargets = 0
116 for target in self.getUserCommandTargets():
117 numTargets += 1
118 try:
119 self.write(out, '')
120 self.write(out, '==== %s ====' % target.id)
121 self.doCommandForTarget(command, target, out)
122 except:
123 self.write(out,
124 'exception while performing command for %s' % target.id)
125 self.write(
126 out, 'type: %s value: %s' % tuple(sys.exc_info()[:2]))
127 self.write(out, '')
128 self.write(out, '')
129 self.write(out, 'DONE in %s seconds on %s targets' %
130 (long(time.time() - startTime), numTargets))
131 REQUEST.RESPONSE.write(footer)
132
133
135 ''' Execute the given UserCommand on the given target
136 '''
137 compiled = self.compile(cmd, target)
138 child = popen2.Popen4(compiled)
139 flags = fcntl.fcntl(child.fromchild, fcntl.F_GETFL)
140 fcntl.fcntl(child.fromchild, fcntl.F_SETFL, flags | os.O_NDELAY)
141 timeout = getattr(target, 'zCommandCommandTimeout', self.defaultTimeout)
142 timeout = max(timeout, 1)
143 endtime = time.time() + timeout
144 self.write(out, '%s' % compiled)
145 self.write(out, '')
146 pollPeriod = 1
147 firstPass = True
148 while time.time() < endtime and (firstPass or child.poll() == -1):
149 firstPass = False
150 r, w, e = select.select([child.fromchild], [], [], pollPeriod)
151 if r:
152 t = child.fromchild.read()
153
154
155
156 if t:
157 self.write(out, t)
158
159 if child.poll() == -1:
160 self.write(out, 'Command timed out for %s' % target.id +
161 ' (timeout is %s seconds)' % timeout)
162 os.kill(child.pid, signal.SIGKILL)
163
164
175
176
177 security.declareProtected(ZEN_VIEW, 'getUserCommandIds')
179 ''' Get the user command ids available in this context
180 '''
181 commandIds = []
182 mychain = self.getAqChainForUserCommands()
183 mychain.reverse()
184 for obj in mychain:
185 if getattr(aq_base(obj), 'userCommands', None):
186 for c in obj.userCommands():
187 commandIds.append(c.id)
188 return commandIds
189
190 security.declareProtected(ZEN_DEFINE_COMMANDS_VIEW, 'getUserCommands')
192 ''' Get the user commands available in this context
193 '''
194 commands = {}
195 mychain = self.getAqChainForUserCommands()
196 mychain.reverse()
197 for obj in mychain:
198 if getattr(aq_base(obj), 'userCommands', None):
199 for c in obj.userCommands():
200 commands[c.id] = c
201 def cmpCommands(a, b):
202 return cmp(a.getId(), b.getId())
203 if not asDict:
204 commands = commands.values()
205 commands.sort(cmpCommands)
206 return commands
207
208
211
212
221
222
239
240 security.declareProtected(ZEN_DEFINE_COMMANDS_VIEW, 'getUserCommand')
242 ''' Returns the command from the current context if it exists
243 '''
244 return self.getUserCommands(asDict=True).get(commandId, None)
245
246
248 ''' Get the environment that provides context for the tales
249 evaluation of a UserCommand.
250 '''
251
252 return {
253 'target': self,
254 'here': self,
255 'nothing': None,
256 'now': DateTime()
257 }
258
259
261 ''' Called by Commandable.doCommand() to ascertain objects on which
262 a UserCommand should be executed.
263 '''
264 raise 'must be implemented by subclass'
265
266
267 - def write(self, out, lines):
268 ''' Output (maybe partial) result text from a UserCommand.
269 '''
270
271
272 startLine = '<tr><td class="tablevalues">'
273 endLine = '</td></tr>\n'
274 if out:
275 if not isinstance(lines, list):
276 lines = [lines]
277 for l in lines:
278 if not isinstance(l, str):
279 l = str(l)
280 l = l.strip()
281 l = cgi.escape(l)
282 l = l.replace('\n', endLine + startLine)
283 out.write(startLine + l + endLine)
284
285 InitializeClass(Commandable)
286