added a variety of updates to templates, to reference each other.
[monitor.git] / zabbix / zabbixsite.py
1 #!/usr/bin/python
2
3 from os import getcwd
4 from os.path import dirname, exists, join
5 import sys
6 import md5
7 import glob
8
9 from monitor import config
10 from monitor.database.dborm import zab_session as session
11 from monitor.database.zabbixapi.model import *
12 from monitor.database.zabbixapi.emailZabbix import *
13 from monitor.database.zabbixapi import defines
14 from monitor.util.file import *
15
16
17
18 HOSTGROUP_NAME="%s_hostgroup"
19 USERGROUP_NAME="%s_usergroup"
20         
21 DISCOVERY_RULE_NAME="discovery rule for %s"
22 DISCOVERY_ACTION_NAME="Auto-discover %s action"
23 ESCALATION_ACTION_NAME="Escalation Action for %s"
24
25 def delete_site(loginbase):
26
27         # get host group, usrgrp
28         # get all users in usrgrp, delete each
29         usergroupname = USERGROUP_NAME % loginbase
30         hostgroupname = HOSTGROUP_NAME % loginbase
31         discovery_action_name = DISCOVERY_ACTION_NAME % loginbase
32         discovery_rule_name = DISCOVERY_RULE_NAME % loginbase
33         escalation_action_name = ESCALATION_ACTION_NAME % loginbase
34
35         ug = UsrGrp.get_by(name=usergroupname)
36         if ug:
37                 for user in ug.user_list:
38                         # remove user from group, if a member of no other groups, 
39                         # delete user.
40                         #user.delete()
41                         pass
42                 ug.delete()
43
44         hg = HostGroup.get_by(name=hostgroupname)
45         if hg: 
46                 # figure out how to delete all the hosts...
47                 # NOTE: hosts are listed in hg.host_list
48                 for host in hg.host_list:
49                         host.delete()
50                 hg.delete()
51
52         # delete dr
53         dr = DiscoveryRule.get_by(name=discovery_rule_name)
54         if dr: dr.delete()
55
56         da = Action.get_by(name=discovery_action_name)
57         if da: da.delete()
58
59         ea = Action.get_by(name=escalation_action_name)
60         if ea: ea.delete()
61
62         return
63
64
65 # NOTE: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
66 ##     These functions can ONLY be run when the server and gui are offline.
67 ##     Any changes to the db while this is running risks introducing a failure
68 ##         to commit, and therefore error.
69 # NOTE: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
70 def setup_global():
71         # GLOBAL:
72         #       update mediatype for email.
73         ############################### MAIL
74         print "checking for MediaType Email"
75         mediatype = MediaType.get_by(description="Email")
76         if not mediatype:
77                 print "ERROR:  There is no defined media type for 'Email'"
78                 raise Exception("No Email Media type in Zabbix db")
79
80         print "checking for correct configuration"
81         mediatype = MediaType.get_by(smtp_email=config.from_email)
82         if not mediatype:
83                 mediatype = MediaType.get_by(description="Email")
84                 # NOTE: assumes smtp server is local to this machine.
85                 print "updating email server configuration"
86                 mediatype.smtp_server='localhost'
87                 mediatype.smtp_helo=".".join(config.MONITOR_HOSTNAME.split('.')[1:])
88                 mediatype.smtp_email=config.from_email
89
90         ############################# EMAIL
91         mailtxt.reformat({'hostname' : config.MONITOR_HOSTNAME, 
92                                           'support_email' : config.support_email})
93
94         ############################### CENTRAL SERVER
95         print "checking zabbix server host info"
96         zabbixserver = Host.get_by(host="ZABBIX Server")
97         if zabbixserver:
98                 # TODO: verify that this works.  it has failed once on fresh
99                 # install... not sure why.
100                 print "Removing default Zabbix server entry"
101                 zabbixserver.delete()
102
103                 # NOTE: creating a host and assigning a template cannot work 
104                 #       due to the crazy item, trigger, action
105                 #               copying that the php code does during a host add.
106                 # NOTE: Instead, reformat any *xml.in templates and import those
107                 #               during /etc/plc.d/monitor sync
108                 for file in glob.glob("%s/zabbix/templates/*.xml.in" % config.MONITOR_SCRIPT_ROOT):
109                         if 'zabbix_server' in file:
110                                 buf = loadFile(file)
111                                 args = {'hostname' : config.MONITOR_HOSTNAME, 'ip' : config.MONITOR_IP}
112                                 dumpFile(file[:-3], buf % args)
113
114
115         ##################### SCRIPTS 
116         ## TODO: add calls to check/reset the boot states.
117         print "checking scripts"
118         script1 = Script.find_or_create(name="RebootNode",
119                                                                         set_if_new = {
120                                                                                 'command':"%s/reboot.py {HOST.CONN}" % config.MONITOR_SCRIPT_ROOT,
121                                                                                 'host_access':3 # r/w)
122                                                                         })
123         script2 = Script.find_or_create(name="NMap",
124                                                         set_if_new = {
125                                                                 'command':"/usr/bin/nmap -A {HOST.CONN}",
126                                                                 'host_access':2 # r/o)
127                                                 })
128         return
129
130 def merge_iplist(iplist):
131         # TODO:  rewrite addresses as x.x.x.y-z rather than x.x.x.y,x.x.x.z if y-z==1
132         ips = iplist.split(',')
133         ips.sort()
134         prev=None
135         newlist=""
136         for ip in ips:
137                 fields = ip.split('.')
138                 first = ".".join(fields[:2])
139                 last  = int(fields[3])
140                 if prev:
141                         if last - prev == 1:
142                                 pass
143                 prev=last
144                 newlist += "%s,"
145         return newlist[:-1]
146
147 def setup_site(loginbase, techemail, piemail, iplist):
148
149         # TODO: send a message when host is discovered.
150
151         # TODO: update 'discovered' hosts with dns name.
152         # TODO: remove old nodes that are no longer in the plcdb.
153         # TODO: remove old users that are no longer in the plcdb.
154         # TODO: consider creating two user groups for Tech & PI emails
155
156         # NOTE: setup default valus for EMAIL
157         mailtxt.reformat({'hostname' : config.MONITOR_HOSTNAME, 
158                                           'support_email' : config.support_email})
159
160         # NOTE: verify arguments
161         if len(iplist) > 255:
162                 raise Exception("iplist length is too long!")
163
164         BI_WEEKLY_ESC_PERIOD = int(60*60*24)
165         #BI_WEEKLY_ESC_PERIOD = int(60) # testing...
166
167         # User Group
168         site_user_group = UsrGrp.find_or_create(name=USERGROUP_NAME % loginbase)
169         for user in set(techemail + piemail + [config.cc_email]):
170                 if not user: continue
171                 # USER
172                 u = User.find_or_create(alias=user, type=1,
173                                                                 set_if_new={'passwd' : md5.md5(user).hexdigest()},
174                                                                 # exec_if_new avoids creating a Media object that
175                                                                 # will not actually be used, if the user already exists
176                                                                 exec_if_new=lambda obj: \
177                                                                 obj.media_list.append( Media(mediatypeid=1, sendto=user)))
178
179                 if site_user_group not in u.usrgrp_list:
180                         u.append_group(site_user_group)
181
182         # HOST GROUP
183         plc_host_group = HostGroup.find_or_create(name="MyPLC Hosts")
184         site_host_group = HostGroup.find_or_create(name=HOSTGROUP_NAME % loginbase)
185         plctemplate = Host.get_by(host="Template_Linux_PLC_Host")
186         escalation_action_name = ESCALATION_ACTION_NAME % loginbase
187         discovery_action_name = DISCOVERY_ACTION_NAME % loginbase
188         discovery_rule_name = DISCOVERY_RULE_NAME % loginbase
189
190         # ADD hg to ug
191         if site_host_group not in site_user_group.hostgroup_list:
192                 site_user_group.append_hostgroup(site_host_group)
193
194         # DISCOVERY RULE & CHECK
195         dr = DiscoveryRule.find_or_create(name=discovery_rule_name,
196                           delay=3600,
197                           proxy_hostid=0,
198                           set_if_new = {'iprange':iplist},
199                           exec_if_new=lambda obj: \
200                                 obj.discoverycheck_list.append( DiscoveryCheck(type=9, 
201                                                                                 key_="system.uname", ports=10050) )
202                         )
203         if dr.iprange != iplist:
204                 dr.iprange = iplist
205                 
206
207         # DISCOVERY ACTION for these servers
208         a = Action.find_or_create(name=discovery_action_name,
209                         eventsource=defines.EVENT_SOURCE_DISCOVERY,
210                         status=defines.DRULE_STATUS_ACTIVE,
211                         evaltype=defines.ACTION_EVAL_TYPE_AND_OR)
212         if len(a.actioncondition_list) == 0:
213                 a.actioncondition_list=[
214                                         # Host IP Matches
215                                         ActionCondition(
216                                                 conditiontype=defines.CONDITION_TYPE_DHOST_IP,
217                                                 operator=defines.CONDITION_OPERATOR_EQUAL,
218                                                 value=iplist),
219                                         # AND, Service type is Zabbix agent
220                                         ActionCondition(
221                                                 conditiontype=defines.CONDITION_TYPE_DSERVICE_TYPE,
222                                                 operator=defines.CONDITION_OPERATOR_EQUAL,
223                                                 value=defines.SVC_AGENT),
224                                         # AND, Received system.uname value like 'Linux'
225                                         ActionCondition(
226                                                 conditiontype=defines.CONDITION_TYPE_DVALUE,
227                                                 operator=defines.CONDITION_OPERATOR_LIKE,
228                                                 value="Linux"),
229                                         # AND, Discovery status is Discover
230                                         ActionCondition(
231                                                 conditiontype=defines.CONDITION_TYPE_DSTATUS,
232                                                 operator=defines.CONDITION_OPERATOR_EQUAL,
233                                                 value=defines.DOBJECT_STATUS_DISCOVER),
234                                 ]
235                                 # THEN
236                 a.actionoperation_list=[
237                                         # Add Host
238                                         ActionOperation(
239                                                 operationtype=defines.OPERATION_TYPE_HOST_ADD,
240                                                 object=0, objectid=0,
241                                                 esc_period=0, esc_step_from=1, esc_step_to=1),
242                                         # Add To Group PLC Hosts
243                                         ActionOperation(
244                                                 operationtype=defines.OPERATION_TYPE_GROUP_ADD,
245                                                 object=0, objectid=plc_host_group.groupid,
246                                                 esc_period=0, esc_step_from=1, esc_step_to=1),
247                                         # Add To Group LoginbaseSiteGroup
248                                         ActionOperation(
249                                                 operationtype=defines.OPERATION_TYPE_GROUP_ADD,
250                                                 object=0, objectid=site_host_group.groupid,
251                                                 esc_period=0, esc_step_from=1, esc_step_to=1),
252                                         # Link to Template 'Template_Linux_Minimal'
253                                         ActionOperation(
254                                                 operationtype=defines.OPERATION_TYPE_TEMPLATE_ADD,
255                                                 object=0, objectid=plctemplate.hostid,
256                                                 esc_period=0, esc_step_from=1, esc_step_to=1),
257                                 ]
258         else:
259                 # TODO: verify iplist is up-to-date
260                 # NOTE: len(a.actioncondition_list) > 0
261                 ip_condition  = a.actioncondition_list[0]
262                 assert ip_condition.conditiontype == defines.CONDITION_TYPE_DHOST_IP
263                 if ip_condition.value != iplist:
264                         ip_condition.value = iplist
265
266         # ESCALATION ACTION for these servers
267         ea = Action.find_or_create(name=escalation_action_name,
268                         eventsource=defines.EVENT_SOURCE_TRIGGERS,
269                         status=defines.ACTION_STATUS_ENABLED,
270                         evaltype=defines.ACTION_EVAL_TYPE_AND_OR,
271                         esc_period=BI_WEEKLY_ESC_PERIOD,        # three days
272                         recovery_msg=1,
273                         set_if_new={
274                                 'r_shortdata':"Thank you for maintaining {HOSTNAME}!",
275                                 'r_longdata': mailtxt.thankyou_nodeup, }
276                         )
277         if len(ea.actioncondition_list) == 0:
278                         # THEN this is a new entry
279                 print "SETTING UP ESCALATION ACTION"
280                 ea.actioncondition_list=[
281                                 ActionCondition(conditiontype=defines.CONDITION_TYPE_TRIGGER_VALUE, 
282                                                                 operator=defines.CONDITION_OPERATOR_EQUAL, 
283                                                                 value=defines.TRIGGER_VALUE_TRUE),
284                                 ActionCondition(conditiontype=defines.CONDITION_TYPE_TRIGGER_NAME, 
285                                                                 operator=defines.CONDITION_OPERATOR_LIKE, 
286                                                                 value="is unreachable"),
287                                 ActionCondition(conditiontype=defines.CONDITION_TYPE_HOST_GROUP, 
288                                                                 operator=defines.CONDITION_OPERATOR_EQUAL, 
289                                                                 value=site_host_group.groupid),
290                         ]
291                 ea.actionoperation_list=[
292                                 # STAGE 1
293                                 ActionOperation(operationtype=defines.OPERATION_TYPE_MESSAGE,
294                                         shortdata=mailtxt.nodedown_one_subject,
295                                         longdata=mailtxt.nodedown_one,
296                                         object=defines.OPERATION_OBJECT_GROUP, 
297                                         objectid=site_user_group.usrgrpid, 
298                                         esc_period=0, esc_step_to=3, esc_step_from=3, 
299                                         operationcondition_list=[ OperationConditionNotAck() ] ),
300                                 ActionOperation(operationtype=defines.OPERATION_TYPE_MESSAGE,
301                                         shortdata=mailtxt.nodedown_one_subject,
302                                         longdata=mailtxt.nodedown_one,
303                                         object=defines.OPERATION_OBJECT_GROUP, 
304                                         objectid=site_user_group.usrgrpid, 
305                                         esc_period=0, esc_step_to=7, esc_step_from=7, 
306                                         operationcondition_list=[ OperationConditionNotAck() ] ),
307                                 # STAGE 2
308                                 ActionOperation(operationtype=defines.OPERATION_TYPE_COMMAND, 
309                                         esc_step_from=10, esc_step_to=10, 
310                                         esc_period=0,
311                                         shortdata="",
312                                         longdata="%s:%s/checkslices.py {HOSTNAME} disablesite" % ( config.MONITOR_HOSTNAME, config.MONITOR_SCRIPT_ROOT ), 
313                                         operationcondition_list=[ OperationConditionNotAck() ]),
314                                 ActionOperation(operationtype=defines.OPERATION_TYPE_MESSAGE, 
315                                         shortdata=mailtxt.nodedown_two_subject,
316                                         longdata=mailtxt.nodedown_two,
317                                         esc_step_from=10, esc_step_to=10, 
318                                         esc_period=0, 
319                                         object=defines.OPERATION_OBJECT_GROUP, 
320                                         objectid=site_user_group.usrgrpid, 
321                                         operationcondition_list=[ OperationConditionNotAck() ] ), 
322                                 ActionOperation(operationtype=defines.OPERATION_TYPE_MESSAGE, 
323                                         shortdata=mailtxt.nodedown_two_subject,
324                                         longdata=mailtxt.nodedown_two,
325                                         esc_step_from=14, esc_step_to=14, 
326                                         esc_period=0, 
327                                         object=defines.OPERATION_OBJECT_GROUP, 
328                                         objectid=site_user_group.usrgrpid, 
329                                         operationcondition_list=[ OperationConditionNotAck() ] ), 
330
331                                 # STAGE 3
332                                 ActionOperation(operationtype=defines.OPERATION_TYPE_COMMAND, 
333                                         esc_step_from=17, esc_step_to=17, 
334                                         esc_period=0, 
335                                         shortdata="",
336                                         longdata="%s:%s/checkslices.py {HOSTNAME} disableslices" % ( config.MONITOR_HOSTNAME, config.MONITOR_SCRIPT_ROOT ), 
337                                         # TODO: send notice to users of slices
338                                         operationcondition_list=[ OperationConditionNotAck() ]),
339                                 ActionOperation(operationtype=defines.OPERATION_TYPE_MESSAGE, 
340                                         shortdata=mailtxt.nodedown_three_subject,
341                                         longdata=mailtxt.nodedown_three,
342                                         esc_step_from=17, esc_step_to=17, 
343                                         esc_period=0, 
344                                         object=defines.OPERATION_OBJECT_GROUP, 
345                                         objectid=site_user_group.usrgrpid, 
346                                         operationcondition_list=[ OperationConditionNotAck() ] ), 
347                                 # STAGE 4++
348                                 ActionOperation(operationtype=defines.OPERATION_TYPE_COMMAND, 
349                                         esc_step_from=21, esc_step_to=0, 
350                                         esc_period=int(BI_WEEKLY_ESC_PERIOD*3.5),
351                                         shortdata="",
352                                         longdata="%s:%s/checkslices.py {HOSTNAME} forever" % ( config.MONITOR_HOSTNAME, config.MONITOR_SCRIPT_ROOT), 
353                                         operationcondition_list=[ OperationConditionNotAck() ]),
354                                 ActionOperation(operationtype=defines.OPERATION_TYPE_MESSAGE, 
355                                         shortdata=mailtxt.nodedown_four_subject,
356                                         longdata=mailtxt.nodedown_four,
357                                         esc_step_from=21, esc_step_to=0, 
358                                         esc_period=int(BI_WEEKLY_ESC_PERIOD*3.5),
359                                         object=defines.OPERATION_OBJECT_GROUP, 
360                                         objectid=site_user_group.usrgrpid, 
361                                         operationcondition_list=[ OperationConditionNotAck() ] ), 
362                         ]
363
364 if __name__ == "__main__":
365         setup_global()
366         session.flush()