| Trees | Indices | Help |
|
|---|
|
|
1 ###########################################################################
2 #
3 # This program is part of Zenoss Core, an open source monitoring platform.
4 # Copyright (C) 2007, Zenoss Inc.
5 #
6 # This program is free software; you can redistribute it and/or modify it
7 # under the terms of the GNU General Public License version 2 as published by
8 # the Free Software Foundation.
9 #
10 # For complete information please visit: http://www.zenoss.com/oss/
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 # seconds
44
45 security = ClassSecurityInfo()
46
47 security.declareProtected(ZEN_DEFINE_COMMANDS_EDIT, 'manage_addUserCommand')
49 "Add a UserCommand to this device"
50 uc = None
51 if newId:
52 uc = UserCommand(newId)
53 self.userCommands._setObject(newId, uc)
54 if self.meta_type == 'Device':
55 self.setLastChange()
56 uc.description = desc
57 uc.command = cmd
58 if REQUEST:
59 if uc:
60 url = '%s/userCommands/%s?message=%s' % (
61 self.getPrimaryUrlPath(), uc.id, 'Command Added')
62 REQUEST['RESPONSE'].redirect(url)
63 REQUEST['message'] = 'Command Added'
64 return self.callZenScreen(REQUEST)
65 return uc
66
67
68 security.declareProtected(ZEN_DEFINE_COMMANDS_EDIT,
69 'manage_deleteUserCommand')
71 "Delete User Command(s) to this device"
72 import types
73 if type(ids) in types.StringTypes:
74 ids = [ids]
75 for id in ids:
76 self.userCommands._delObject(id)
77 if self.meta_type == 'Device':
78 self.setLastChange()
79 if REQUEST:
80 REQUEST['message'] = "Command(s) Deleted"
81 return self.callZenScreen(REQUEST)
82
83 security.declareProtected(ZEN_DEFINE_COMMANDS_EDIT,
84 'manage_editUserCommand')
86 ''' Want to redirect back to management tab after a save
87 '''
88 command = self.getUserCommand(commandId)
89 if command:
90 command.manage_changeProperties(**REQUEST.form)
91 return self.redirectToUserCommands(REQUEST)
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 # This could be changed so that output is sent through a
100 # logger so that non web-based code can produce output.
101 # Not necessary for now.
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 # We are sometimes getting to this point without any data
154 # from child.fromchild. I don't think that should happen
155 # but the conditional below seems to be necessary.
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
166 ''' Evaluate command as a tales expression
167 '''
168 exp = "string:"+ cmd.command
169 compiled = talesCompile(exp)
170 environ = target.getUserCommandEnvironment()
171 res = compiled(getEngine().getContext(environ))
172 if isinstance(res, Exception):
173 raise res
174 return res
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
210 return aq_chain(self.primaryAq())
211
212
214 ''' Redirect to the page which lists UserCommands
215 for this Commandable object.
216 '''
217 url = self.getUrlForUserCommands()
218 if url:
219 return REQUEST.RESPONSE.redirect(url)
220 return self.callZenScreen(REQUEST)
221
222
224 ''' Return url for page which manages user commands
225 '''
226 # This should be overridden by subclasses of Commandable
227 return self.getPrimaryUrlPath()
228
229 candidates = [a for a in self.factory_type_information[0]['actions']
230 if a['name'] == 'Administration']
231 if candidates:
232 action = candidates[0]
233 url = '%s/%s' % (self.getPrimaryUrlPath(), action['action'])
234 if commandId:
235 url += '?commandId=%s' % commandId
236 else:
237 url = ''
238 return url
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 # Overridden by Service and Device
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
268 ''' Output (maybe partial) result text from a UserCommand.
269 '''
270 # Looks like firefox renders progressive output more smoothly
271 # if each line is stuck into a table row.
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
| Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0beta1 on Thu Oct 25 16:28:43 2007 | http://epydoc.sourceforge.net |