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