1
2
3
4
5
6
7
8
9
10
11 import re
12 import logging
13 from Acquisition import aq_base
14 from Products.Five.browser import BrowserView
15 from Products.Five.browser.pagetemplatefile import ZopeTwoPageTemplateFile
16 from Products.ZenModel.IpNetwork import AutoDiscoveryJob
17 from Products.ZenWidgets.messaging import IMessageSender
18 from Products.ZenUtils import Ext
19 from Products.ZenUtils.jsonutils import json
20 from Products.ZenMessaging.audit import audit
21
22 _is_network = lambda x: bool(re.compile(r'^(\d+\.){3}\d+\/\d+$').search(x))
23 _is_range = lambda x: bool(re.compile(r'^(\d+\.){3}\d+\-\d+$').search(x))
24 log = logging.getLogger("zen.quickstart")
27 """
28 Standard macros for the quickstart.
29 """
30 template = ZopeTwoPageTemplateFile('templates/quickstart_macros.pt')
31
34
37 """
38 Displays the steps the user will soon be completing. The anticipation!
39 """
40 __call__ = ZopeTwoPageTemplateFile('templates/outline.pt')
41
44 """
45 Creates the initial user and sets the admin password.
46 """
47 __call__ = ZopeTwoPageTemplateFile('templates/createuser.pt')
48
51 """
52 Specify devices to be added.
53 """
54 @property
56 try:
57 import ZenPacks.zenoss.LDAPAuthenticator
58
59 return "true"
60 except ImportError:
61 return "false"
62
63 @json
65 """
66 Format the value of Devices.Discovered.zSnmpCommunities for a textarea
67 """
68 devclass = self.context.dmd.Devices.Discovered.primaryAq()
69 return '\n'.join(devclass.zSnmpCommunities)
70
72 """
73 Walks all device classes building a list of description/protocol pairs.
74 """
75 ALLOWED_PROTOCOLS = ('SSH', 'SNMP', 'WMI')
76 devclass = self.context.dmd.Devices
77 orgs = devclass.getSubOrganizers()
78 types = []
79 for org in orgs:
80
81 if not hasattr(aq_base(org), 'devtypes') or not org.devtypes:
82 continue
83 for t in org.devtypes:
84 try:
85 desc, ptcl = t
86 except ValueError:
87 continue
88
89
90 if not ptcl or not desc:
91 continue
92
93
94 if ptcl not in ALLOWED_PROTOCOLS: continue
95 types.append((org.getOrganizerName(), desc, ptcl))
96 return types
97
98 @json
100 """
101 Build an object for populating an Ext ComboBox representing "device
102 types," which should exactly correspond to DeviceClasses in the system.
103
104 This method iterates over a predetermined list of types we might want
105 to see and checks each DeviceClass for existence (i.e., is the
106 appropriate ZenPack installed?).
107 """
108
109 types = {'win':[], 'ssh':[], 'snmp':[]}
110 for t in self._assemble_types_list():
111 if t[2]=='WMI': types['win'].append(t)
112 elif t[2]=='SNMP': types['snmp'].append(t)
113 elif t[2]=='SSH': types['ssh'].append(t)
114
115 def dev_class_exists(path):
116 """
117 Return a boolean indicating whether the specified DeviceClass
118 exists.
119 """
120 try:
121 self.context.unrestrictedTraverse(
122 '/zport/dmd/Devices' + path)
123 except AttributeError:
124 return False
125 else:
126 return True
127
128 def format_type(credtype, classpath, description, protocol):
129 """
130 Turn information representing a device class into a dictionary of
131 the format our ComboBox expects.
132 """
133 value = '%s_%s' % (classpath, credtype)
134 return dict(value=value,
135 shortdesc="%s (%s)" % (description, protocol),
136 description=description, protocol=protocol)
137
138
139 response = []
140 for credtype, devtypes in types.iteritems():
141 for devtype in devtypes:
142
143 if dev_class_exists(devtype[0]):
144
145 response.append(format_type(credtype, *devtype))
146
147
148 response.sort(key=lambda x:x['description'])
149
150
151
152 return dict(types=response)
153
154
155 @Ext.form_action
157 response = Ext.FormResponse()
158 submitted = self.request.form.get('network', [])
159 if isinstance(submitted, basestring):
160 submitted = [submitted]
161 zProperties = {
162 'zCommandUsername': self.request.form.get('sshusername'),
163 'zCommandPassword': self.request.form.get('sshpass'),
164 'zWinUser': self.request.form.get('winusername'),
165 'zWinPassword': self.request.form.get('winpass'),
166 'zSnmpCommunities': self.request.form.get('snmpcommunities').splitlines()
167 }
168
169 nets = []
170 ranges = []
171 for row in submitted:
172 if _is_network(row): nets.append(row)
173 elif _is_range(row): ranges.append(row)
174 if not nets and not ranges:
175 response.error('network',
176 'You must enter at least one network or IP range.')
177 if nets:
178 for net in nets:
179
180
181 _n = self.context.dmd.Networks.createNet(net)
182 try:
183 netdesc = ("network %s" % nets[0] if len(nets)==1
184 else "%s networks" % len(nets))
185 self.context.JobManager.addJob(
186 AutoDiscoveryJob,
187 description="Discover %s" % netdesc,
188 kwargs=dict(
189 nets=nets,
190 zProperties=zProperties
191 )
192 )
193 except Exception, e:
194 log.exception(e)
195 response.error('network', 'There was an error scheduling this '
196 'job. Please check your installation and try '
197 'again.')
198 else:
199 IMessageSender(self.context).sendToUser(
200 'Autodiscovery Task Created',
201 'Discovery of the following networks is in progress: %s' % (
202 ', '.join(nets))
203 )
204 if ranges:
205
206
207 try:
208 rangedesc = ("IP range %s" % ranges[0]
209 if len(ranges)==1
210 else "%s IP ranges" % len(ranges))
211 self.context.JobManager.addJob(
212 AutoDiscoveryJob,
213 description="Discover %s" % rangedesc,
214 kwargs=dict(
215 ranges=ranges,
216 zProperties=zProperties
217 )
218 )
219 except Exception, e:
220 log.exception(e)
221 response.error('network', 'There was an error scheduling this '
222 'job. Please check your installation and try '
223 'again.')
224 else:
225 IMessageSender(self.context).sendToUser(
226 'Autodiscovery Task Created',
227 'Discovery of the following IP ranges is in progress: %s' % (
228 ', '.join(ranges))
229 )
230
231 audit('UI.Device.Autodiscovery', networks=','.join(nets), ipRanges=','.join(ranges))
232 response.redirect('/zport/dmd')
233 return response
234
235
236 @Ext.form_action
238
239 response = Ext.FormResponse()
240 devs = filter(lambda x:x.startswith('device_'),
241 self.request.form.keys())
242
243 devnames = filter(lambda x:bool(self.request.form.get(x)), devs)
244 if not devnames:
245 response.error('device_0',
246 'You must enter at least one hostname/IP.')
247 return response
248
249 for k in devs:
250
251 if not self.request.form.get(k): continue
252 idx = k.split('_')[1]
253 devclass, type_ = self.request.form.get(
254 'deviceclass_%s' % idx).split('_')
255
256 if type_=='ssh':
257 zProps = {
258 'zCommandUsername': self.request.form.get('sshuser_%s' % idx),
259 'zCommandPassword': self.request.form.get(
260 'sshpass_%s' % idx),
261 }
262 elif type_=='win':
263 zProps = {
264 'zWinUser': self.request.form.get('winuser_%s' % idx),
265 'zWinPassword': self.request.form.get('winpass_%s' % idx),
266 }
267 elif type_=='snmp':
268 zProps = {
269 'zSnmpCommunities': self.request.form.get(
270 'snmpcomm_%s' % idx
271 ).splitlines()
272 }
273 deviceName = self.request.form.get(k)
274 perfConf = self.context.Monitors.getPerformanceMonitor('localhost')
275 perfConf.addDeviceCreationJob(deviceName=deviceName,
276 devicePath=devclass, zProperties=zProps, discoverProto='auto')
277 deviceClassUid = '/Devices' + devclass
278 deviceUid = '/'.join([deviceClassUid, 'devices', deviceName])
279 audit('UI.Device.Add', deviceUid, deviceClass=deviceClassUid, model=True)
280 devnames = [self.request.form.get(dev) for dev in devs]
281 IMessageSender(self.context).sendToUser(
282 'Devices Added',
283 'Modeling of the following devices has been scheduled: %s' % (
284 ', '.join(filter(None, devnames))
285 )
286 )
287 response.redirect('/zport/dmd')
288 return response
289